diff --git a/kded/daemon.cpp b/kded/daemon.cpp index 3322472..4bc98be 100644 --- a/kded/daemon.cpp +++ b/kded/daemon.cpp @@ -1,504 +1,502 @@ /************************************************************************************* * Copyright (C) 2012 by Alejandro Fiestas Olivares * * Copyright 2016 by 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 "daemon.h" #include "serializer.h" #include "generator.h" #include "device.h" #include "kscreenadaptor.h" #include "kscreen_daemon_debug.h" #include "osdmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KScreenDaemonFactory, "kscreen.json", registerPlugin();) KScreenDaemon::KScreenDaemon(QObject* parent, const QList< QVariant >& ) : KDEDModule(parent) , m_monitoredConfig(nullptr) , m_iteration(Generator::None) , m_monitoring(false) , m_changeCompressor(new QTimer(this)) , m_buttonTimer(new QTimer(this)) , m_saveTimer(new QTimer(this)) , m_lidClosedTimer(new QTimer(this)) { KScreen::Log::instance(); QMetaObject::invokeMethod(this, "requestConfig", Qt::QueuedConnection); } void KScreenDaemon::requestConfig() { connect(new KScreen::GetConfigOperation, &KScreen::GetConfigOperation::finished, this, &KScreenDaemon::configReady); } void KScreenDaemon::configReady(KScreen::ConfigOperation* op) { if (op->hasError()) { return; } m_monitoredConfig = qobject_cast(op)->config(); qCDebug(KSCREEN_KDED) << "Config" << m_monitoredConfig.data() << "is ready"; KScreen::ConfigMonitor::instance()->addConfig(m_monitoredConfig); init(); } KScreenDaemon::~KScreenDaemon() { Generator::destroy(); Device::destroy(); } void KScreenDaemon::init() { KActionCollection *coll = new KActionCollection(this); QAction* action = coll->addAction(QStringLiteral("display")); action->setText(i18n("Switch Display" )); QList switchDisplayShortcuts({Qt::Key_Display, Qt::MetaModifier + Qt::Key_P}); KGlobalAccel::self()->setGlobalShortcut(action, switchDisplayShortcuts); connect(action, &QAction::triggered, [&](bool) { displayButton(); }); new KScreenAdaptor(this); // Initialize OSD manager to register its dbus interface KScreen::OsdManager::self(); m_buttonTimer->setInterval(300); m_buttonTimer->setSingleShot(true); connect(m_buttonTimer, &QTimer::timeout, this, &KScreenDaemon::applyGenericConfig); m_saveTimer->setInterval(300); m_saveTimer->setSingleShot(true); connect(m_saveTimer, &QTimer::timeout, this, &KScreenDaemon::saveCurrentConfig); m_changeCompressor->setInterval(10); m_changeCompressor->setSingleShot(true); connect(m_changeCompressor, &QTimer::timeout, this, &KScreenDaemon::applyConfig); m_lidClosedTimer->setInterval(1000); m_lidClosedTimer->setSingleShot(true); connect(m_lidClosedTimer, &QTimer::timeout, this, &KScreenDaemon::lidClosedTimeout); connect(Device::self(), &Device::lidClosedChanged, this, &KScreenDaemon::lidClosedChanged); connect(Device::self(), &Device::resumingFromSuspend, this, [&]() { KScreen::Log::instance()->setContext("resuming"); qCDebug(KSCREEN_KDED) << "Resumed from suspend, checking for screen changes"; // We don't care about the result, we just want to force the backend // to query XRandR so that it will detect possible changes that happened // while the computer was suspended, and will emit the change events. new KScreen::GetConfigOperation(KScreen::GetConfigOperation::NoEDID, this); }); connect(Device::self(), &Device::aboutToSuspend, this, [&]() { qCDebug(KSCREEN_KDED) << "System is going to suspend, won't be changing config (waited for " << (m_lidClosedTimer->interval() - m_lidClosedTimer->remainingTime()) << "ms)"; m_lidClosedTimer->stop(); }); connect(Generator::self(), &Generator::ready, this, &KScreenDaemon::applyConfig); Generator::self()->setCurrentConfig(m_monitoredConfig); monitorConnectedChange(); } void KScreenDaemon::doApplyConfig(const KScreen::ConfigPtr& config) { qCDebug(KSCREEN_KDED) << "doApplyConfig()"; setMonitorForChanges(false); m_monitoredConfig = config; KScreen::ConfigMonitor::instance()->addConfig(m_monitoredConfig); connect(new KScreen::SetConfigOperation(config), &KScreen::SetConfigOperation::finished, this, [&]() { qCDebug(KSCREEN_KDED) << "Config applied"; setMonitorForChanges(true); }); } void KScreenDaemon::applyConfig() { qCDebug(KSCREEN_KDED) << "Applying config"; if (Serializer::configExists(m_monitoredConfig)) { applyKnownConfig(); return; } applyIdealConfig(); } void KScreenDaemon::applyKnownConfig() { const QString configId = Serializer::configId(m_monitoredConfig); qCDebug(KSCREEN_KDED) << "Applying known config" << configId; // We may look for a config that has been set when the lid was closed, Bug: 353029 if (Device::self()->isLaptop() && !Device::self()->isLidClosed()) { Serializer::moveConfig(configId + QStringLiteral("_lidOpened"), configId); } KScreen::ConfigPtr config = Serializer::config(m_monitoredConfig, configId); // It's possible that the Serializer returned a nullptr if (!config || !KScreen::Config::canBeApplied(config, KScreen::Config::ValidityFlag::RequireAtLeastOneEnabledScreen)) { return applyIdealConfig(); } doApplyConfig(config); } -void KScreenDaemon::applyOsdAction(KScreen::OsdAction *self, KScreen::OsdAction::Action action) +void KScreenDaemon::applyOsdAction(KScreen::OsdAction::Action action) { - self->deleteLater(); - switch (action) { case KScreen::OsdAction::NoAction: qCDebug(KSCREEN_KDED) << "OSD: no action"; return; case KScreen::OsdAction::SwitchToInternal: qCDebug(KSCREEN_KDED) << "OSD: switch to internal"; doApplyConfig(Generator::self()->displaySwitch(Generator::TurnOffExternal)); return; case KScreen::OsdAction::SwitchToExternal: qCDebug(KSCREEN_KDED) << "OSD: switch to external"; doApplyConfig(Generator::self()->displaySwitch(Generator::TurnOffEmbedded)); return; case KScreen::OsdAction::ExtendLeft: qCDebug(KSCREEN_KDED) << "OSD: extend left"; doApplyConfig(Generator::self()->displaySwitch(Generator::ExtendToLeft)); return; case KScreen::OsdAction::ExtendRight: qCDebug(KSCREEN_KDED) << "OSD: extend right"; doApplyConfig(Generator::self()->displaySwitch(Generator::ExtendToRight)); return; case KScreen::OsdAction::Clone: qCDebug(KSCREEN_KDED) << "OSD: clone"; doApplyConfig(Generator::self()->displaySwitch(Generator::Clone)); return; } Q_UNREACHABLE(); } void KScreenDaemon::applyIdealConfig() { if (m_monitoredConfig->connectedOutputs().count() < 2) { KScreen::OsdManager::self()->hideOsd(); doApplyConfig(Generator::self()->idealConfig(m_monitoredConfig)); } else { qCDebug(KSCREEN_KDED) << "Getting ideal config from user via OSD..."; auto action = KScreen::OsdManager::self()->showActionSelector(); connect(action, &KScreen::OsdAction::selected, this, &KScreenDaemon::applyOsdAction); } } void logConfig(const KScreen::ConfigPtr &config) { if (config) { foreach (auto o, config->outputs()) { if (o->isConnected()) { qCDebug(KSCREEN_KDED) << o; } } } } void KScreenDaemon::configChanged() { qCDebug(KSCREEN_KDED) << "Change detected"; logConfig(m_monitoredConfig); // Modes may have changed, fix-up current mode id Q_FOREACH(const KScreen::OutputPtr &output, m_monitoredConfig->outputs()) { if (output->isConnected() && output->isEnabled() && output->currentMode().isNull()) { qCDebug(KSCREEN_KDED) << "Current mode" << output->currentModeId() << "invalid, setting preferred mode" << output->preferredModeId(); output->setCurrentModeId(output->preferredModeId()); doApplyConfig(m_monitoredConfig); } } // Reset timer, delay the writeback m_saveTimer->start(); } void KScreenDaemon::saveCurrentConfig() { qCDebug(KSCREEN_KDED) << "Saving current config to file"; // We assume the config is valid, since it's what we got, but we are interested // in the "at least one enabled screen" check const bool valid = KScreen::Config::canBeApplied(m_monitoredConfig, KScreen::Config::ValidityFlag::RequireAtLeastOneEnabledScreen); if (valid) { Serializer::saveConfig(m_monitoredConfig, Serializer::configId(m_monitoredConfig)); logConfig(m_monitoredConfig); } else { qCWarning(KSCREEN_KDED) << "Config does not have at least one screen enabled, WILL NOT save this config, this is not what user wants."; logConfig(m_monitoredConfig); } } void KScreenDaemon::showOsd(const QString &icon, const QString &text) { QDBusMessage msg = QDBusMessage::createMethodCall( QLatin1Literal("org.kde.plasmashell"), QLatin1Literal("/org/kde/osdService"), QLatin1Literal("org.kde.osdService"), QLatin1Literal("showText") ); msg << icon << text; QDBusConnection::sessionBus().asyncCall(msg); } void KScreenDaemon::showOutputIdentifier() { KScreen::OsdManager::self()->showOutputIdentifiers(); } void KScreenDaemon::displayButton() { qCDebug(KSCREEN_KDED) << "displayBtn triggered"; QString message = i18nc("OSD text after XF86Display button press", "No External Display"); if (m_monitoredConfig && m_monitoredConfig->connectedOutputs().count() > 1) { message = i18nc("OSD text after XF86Display button press", "Changing Screen Layout"); } if (m_buttonTimer->isActive()) { qCDebug(KSCREEN_KDED) << "Too fast, cowboy"; return; } m_buttonTimer->start(); } void KScreenDaemon::resetDisplaySwitch() { qCDebug(KSCREEN_KDED) << "resetDisplaySwitch()"; m_iteration = Generator::None; } void KScreenDaemon::applyGenericConfig() { if (m_iteration == Generator::ExtendToRight) { m_iteration = Generator::None; } m_iteration = Generator::DisplaySwitchAction(static_cast(m_iteration) + 1); qCDebug(KSCREEN_KDED) << "displayButton: " << m_iteration; static QHash actionMessages({ {Generator::DisplaySwitchAction::None, i18nc("osd when displaybutton is pressed", "No Action")}, {Generator::DisplaySwitchAction::Clone, i18nc("osd when displaybutton is pressed", "Cloned Display")}, {Generator::DisplaySwitchAction::ExtendToLeft, i18nc("osd when displaybutton is pressed", "Extend Left")}, {Generator::DisplaySwitchAction::TurnOffEmbedded, i18nc("osd when displaybutton is pressed", "External Only")}, {Generator::DisplaySwitchAction::TurnOffExternal, i18nc("osd when displaybutton is pressed", "Internal Only")}, {Generator::DisplaySwitchAction::ExtendToRight, i18nc("osd when displaybutton is pressed", "Extended Right")} }); const QString &message = actionMessages.value(m_iteration); // We delay the OSD for two seconds and hope that X and hardware are done setting everything up. QTimer::singleShot(2000, [message]() { KScreen::OsdManager::self()->showOsd(QStringLiteral("preferences-desktop-display-randr"), message); } ); doApplyConfig(Generator::self()->displaySwitch(m_iteration)); } void KScreenDaemon::lidClosedChanged(bool lidIsClosed) { // Ignore this when we don't have any external monitors, we can't turn off our // only screen if (m_monitoredConfig->connectedOutputs().count() == 1) { return; } if (lidIsClosed) { // Lid is closed, now we wait for couple seconds to find out whether it // will trigger a suspend (see Device::aboutToSuspend), or whether we should // turn off the screen qCDebug(KSCREEN_KDED) << "Lid closed, waiting to see if the computer goes to sleep..."; m_lidClosedTimer->start(); return; } else { qCDebug(KSCREEN_KDED) << "Lid opened!"; // We should have a config with "_lidOpened" suffix lying around. If not, // then the configuration has changed while the lid was closed and we just // use applyConfig() and see what we can do ... const QString openConfigId = Serializer::configId(m_monitoredConfig) + QStringLiteral("_lidOpened"); if (Serializer::configExists(openConfigId)) { const KScreen::ConfigPtr openedConfig = Serializer::config(m_monitoredConfig, openConfigId); Serializer::removeConfig(openConfigId); doApplyConfig(openedConfig); } } } void KScreenDaemon::lidClosedTimeout() { // Make sure nothing has changed in the past second... :-) if (!Device::self()->isLidClosed()) { return; } // If we are here, it means that closing the lid did not result in suspend // action. // FIXME: This could be simply because the suspend took longer than m_lidClosedTimer // timeout. Ideally we need to be able to look into PowerDevil config to see // what's the configured action for lid events, but there's no API to do that // and I'm no parsing PowerDevil's configs... qCDebug(KSCREEN_KDED) << "Lid closed without system going to suspend -> turning off the screen"; for (KScreen::OutputPtr &output : m_monitoredConfig->outputs()) { if (output->type() == KScreen::Output::Panel) { if (output->isConnected() && output->isEnabled()) { // Save the current config with opened lid, just so that we know // how to restore it later const QString configId = Serializer::configId(m_monitoredConfig) + QStringLiteral("_lidOpened"); Serializer::saveConfig(m_monitoredConfig, configId); disableOutput(m_monitoredConfig, output); doApplyConfig(m_monitoredConfig); return; } } } } void KScreenDaemon::outputConnectedChanged() { if (!m_changeCompressor->isActive()) { m_changeCompressor->start(); } resetDisplaySwitch(); KScreen::Output *output = qobject_cast(sender()); qCDebug(KSCREEN_KDED) << "outputConnectedChanged():" << output->name(); if (output->isConnected()) { Q_EMIT outputConnected(output->name()); if (!Serializer::configExists(m_monitoredConfig)) { Q_EMIT unknownOutputConnected(output->name()); } } } void KScreenDaemon::monitorConnectedChange() { KScreen::OutputList outputs = m_monitoredConfig->outputs(); Q_FOREACH(const KScreen::OutputPtr &output, outputs) { connect(output.data(), &KScreen::Output::isConnectedChanged, this, &KScreenDaemon::outputConnectedChanged, Qt::UniqueConnection); } connect(m_monitoredConfig.data(), &KScreen::Config::outputAdded, this, [this] (const KScreen::OutputPtr output) { if (output->isConnected()) { m_changeCompressor->start(); } connect(output.data(), &KScreen::Output::isConnectedChanged, this, &KScreenDaemon::outputConnectedChanged, Qt::UniqueConnection); }, Qt::UniqueConnection ); connect(m_monitoredConfig.data(), &KScreen::Config::outputRemoved, this, &KScreenDaemon::applyConfig, static_cast(Qt::QueuedConnection | Qt::UniqueConnection)); } void KScreenDaemon::setMonitorForChanges(bool enabled) { if (m_monitoring == enabled) { return; } qCDebug(KSCREEN_KDED) << "Monitor for changes: " << enabled; m_monitoring = enabled; if (m_monitoring) { connect(KScreen::ConfigMonitor::instance(), &KScreen::ConfigMonitor::configurationChanged, this, &KScreenDaemon::configChanged, Qt::UniqueConnection); } else { disconnect(KScreen::ConfigMonitor::instance(), &KScreen::ConfigMonitor::configurationChanged, this, &KScreenDaemon::configChanged); } } void KScreenDaemon::disableOutput(KScreen::ConfigPtr &config, KScreen::OutputPtr &output) { const QRect geom = output->geometry(); qCDebug(KSCREEN_KDED) << "Laptop geometry:" << geom << output->pos() << (output->currentMode() ? output->currentMode()->size() : QSize()); // Move all outputs right from the @p output to left for (KScreen::OutputPtr &otherOutput : config->outputs()) { if (otherOutput == output || !otherOutput->isConnected() || !otherOutput->isEnabled()) { continue; } QPoint otherPos = otherOutput->pos(); if (otherPos.x() >= geom.right() && otherPos.y() >= geom.top() && otherPos.y() <= geom.bottom()) { otherPos.setX(otherPos.x() - geom.width()); } qCDebug(KSCREEN_KDED) << "Moving" << otherOutput->name() << "from" << otherOutput->pos() << "to" << otherPos; otherOutput->setPos(otherPos); } // Disable the output output->setEnabled(false); } KScreen::OutputPtr KScreenDaemon::findEmbeddedOutput(const KScreen::ConfigPtr &config) { Q_FOREACH (const KScreen::OutputPtr &output, config->outputs()) { if (output->type() == KScreen::Output::Panel) { return output; } } return KScreen::OutputPtr(); } #include "daemon.moc" diff --git a/kded/daemon.h b/kded/daemon.h index 4294ef3..f95d809 100644 --- a/kded/daemon.h +++ b/kded/daemon.h @@ -1,88 +1,88 @@ /************************************************************************************* * Copyright (C) 2012 by Alejandro Fiestas Olivares * * * * 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 * *************************************************************************************/ #ifndef KSCREEN_DAEMON_H #define KSCREEN_DAEMON_H #include #include #include #include "generator.h" #include "osdmanager.h" class QTimer; namespace KScreen { class ConfigOperation; } class Q_DECL_EXPORT KScreenDaemon : public KDEDModule { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.KScreen") public: KScreenDaemon(QObject *parent, const QList&); virtual ~KScreenDaemon(); public Q_SLOTS: virtual void requestConfig(); void configReady(KScreen::ConfigOperation *op); void init(); void applyConfig(); void applyKnownConfig(); void applyIdealConfig(); void configChanged(); void saveCurrentConfig(); void displayButton(); void resetDisplaySwitch(); void applyGenericConfig(); void lidClosedChanged(bool lidIsClosed); void lidClosedTimeout(); void setMonitorForChanges(bool enabled); void outputConnectedChanged(); void showOutputIdentifier(); - void applyOsdAction(KScreen::OsdAction *self, KScreen::OsdAction::Action action); + void applyOsdAction(KScreen::OsdAction::Action action); Q_SIGNALS: void outputConnected(const QString &outputName); void unknownOutputConnected(const QString &outputName); protected: virtual void doApplyConfig(const KScreen::ConfigPtr &config); void monitorConnectedChange(); static KScreen::OutputPtr findEmbeddedOutput(const KScreen::ConfigPtr &config); void disableOutput(KScreen::ConfigPtr &config, KScreen::OutputPtr &output); void showOsd(const QString &icon, const QString &text); KScreen::ConfigPtr m_monitoredConfig; Generator::DisplaySwitchAction m_iteration; bool m_monitoring; QTimer* m_changeCompressor; QTimer* m_buttonTimer; QTimer* m_saveTimer; QTimer* m_lidClosedTimer; }; #endif /*KSCREEN_DAEMON_H*/ diff --git a/kded/osdmanager.cpp b/kded/osdmanager.cpp index a1bc732..d46bcc3 100644 --- a/kded/osdmanager.cpp +++ b/kded/osdmanager.cpp @@ -1,224 +1,225 @@ /* * 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(this, 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 { 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 { 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" diff --git a/kded/osdmanager.h b/kded/osdmanager.h index 40a305b..75c6250 100644 --- a/kded/osdmanager.h +++ b/kded/osdmanager.h @@ -1,81 +1,81 @@ /* * 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. */ #ifndef OSDM_H #define OSDM_H #include #include #include #include class QmlObject; namespace KScreen { class ConfigOperation; class Osd; class Output; class OsdAction : public QObject { Q_OBJECT public: enum Action { NoAction, SwitchToExternal, SwitchToInternal, Clone, ExtendLeft, ExtendRight }; Q_ENUM(Action) Q_SIGNALS: - void selected(OsdAction *self, Action action); + void selected(Action action); protected: explicit OsdAction(QObject *parent = nullptr); }; class OsdManager : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.kscreen.osdService") public: ~OsdManager() override; static OsdManager* self(); public Q_SLOTS: void showOutputIdentifiers(); void showOsd(const QString &icon, const QString &text); void hideOsd(); OsdAction *showActionSelector(); private: OsdManager(QObject *parent = nullptr); void slotIdentifyOutputs(KScreen::ConfigOperation *op); QMap m_osds; static OsdManager* s_instance; QTimer* m_cleanupTimer; }; } // ns #endif // OSDM_H diff --git a/tests/osd/osdtest.cpp b/tests/osd/osdtest.cpp index e8b4b44..aedae2b 100644 --- a/tests/osd/osdtest.cpp +++ b/tests/osd/osdtest.cpp @@ -1,94 +1,93 @@ /************************************************************************************* * Copyright 2016 Sebastian Kügler * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) any later version. * * * * This library 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 * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************************/ #include "osdtest.h" #include "../../kded/osdmanager.h" #include #include #include #include #include Q_LOGGING_CATEGORY(KSCREEN_KDED, "kscreen.kded") namespace KScreen { OsdTest::OsdTest(QObject *parent) : QObject(parent) { } OsdTest::~OsdTest() { } void OsdTest::showOutputIdentifiers() { if (!m_useDBus) { QTimer::singleShot(5500, qApp, &QCoreApplication::quit); KScreen::OsdManager::self()->showOutputIdentifiers(); } else { QDBusMessage msg = QDBusMessage::createMethodCall( QLatin1Literal("org.kde.kscreen.osdService"), QLatin1Literal("/org/kde/kscreen/osdService"), QLatin1Literal("org.kde.kscreen.osdService"), QLatin1Literal("showOutputIdentifiers") ); //msg << icon << text; QDBusConnection::sessionBus().asyncCall(msg); qCWarning(KSCREEN_KDED) << "Sent dbus message."; QTimer::singleShot(500, qApp, &QCoreApplication::quit); } } void OsdTest::setUseDBus(bool yesno) { m_useDBus = yesno; } void OsdTest::showGenericOsd(const QString& icon, const QString& message) { if (!m_useDBus) { QTimer::singleShot(5500, qApp, &QCoreApplication::quit); KScreen::OsdManager::self()->showOsd(!icon.isEmpty() ? icon : QStringLiteral("preferences-desktop-display-randr"), !message.isEmpty() ? message : QStringLiteral("On-Screen-Display")); } else { qCWarning(KSCREEN_KDED) << "Implement me."; QTimer::singleShot(100, qApp, &QCoreApplication::quit); } } void OsdTest::showActionSelector() { if (!m_useDBus) { auto action = KScreen::OsdManager::self()->showActionSelector(); connect(action, &KScreen::OsdAction::selected, - [](KScreen::OsdAction *self, KScreen::OsdAction::Action action) { - self->deleteLater(); + [](KScreen::OsdAction::Action action) { qCDebug(KSCREEN_KDED) << "Selected action:" << action; qApp->quit(); }); } else { qCWarning(KSCREEN_KDED) << "Implement me."; QTimer::singleShot(100, qApp, &QCoreApplication::quit); } } } // ns