diff --git a/kcms/kded/kcmkded.cpp b/kcms/kded/kcmkded.cpp index 011b5844e..ebf472690 100644 --- a/kcms/kded/kcmkded.cpp +++ b/kcms/kded/kcmkded.cpp @@ -1,512 +1,504 @@ // vim: noexpandtab shiftwidth=4 tabstop=4 /* This file is part of the KDE project Copyright (C) 2002 Daniel Molkentin 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kcmkded.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY(KDEDFactory, registerPlugin(); ) K_EXPORT_PLUGIN(KDEDFactory("kcmkded")) Q_LOGGING_CATEGORY(KCM_KDED, "kcm_kded") enum OnDemandColumns { OnDemandService = 0, OnDemandStatus = 1, OnDemandDescription = 2 }; enum StartupColumns { StartupUse = 0, StartupService = 1, StartupStatus = 2, StartupDescription = 3 }; static const int LibraryRole = Qt::UserRole + 1; KDEDConfig::KDEDConfig(QWidget* parent, const QVariantList &) : KCModule( parent ) { KAboutData *about = new KAboutData( I18N_NOOP( "kcmkded" ), i18n( "KDE Service Manager" ), QStringLiteral("1.0"), QString(), KAboutLicense::GPL, i18n( "(c) 2002 Daniel Molkentin" ) ); about->addAuthor(i18n("Daniel Molkentin"), QString(),QStringLiteral("molkentin@kde.org")); setAboutData( about ); setButtons(Apply|Default|Help); setQuickHelp( i18n("

Service Manager

This module allows you to have an overview of all plugins of the " "KDE Daemon, also referred to as KDE Services. Generally, there are two types of service:

" "
  • Services invoked at startup
  • Services called on demand
" "

The latter are only listed for convenience. The startup services can be started and stopped. " "In Administrator mode, you can also define whether services should be loaded at startup.

" "

Use this with care: some services are vital for Plasma; do not deactivate services if you" " do not know what you are doing.

")); RUNNING = i18n("Running")+' '; NOT_RUNNING = i18n("Not running")+' '; QVBoxLayout *lay = new QVBoxLayout( this ); lay->setMargin( 0 ); QGroupBox *gb = new QGroupBox( i18n("Load-on-Demand Services"), this ); gb->setWhatsThis( i18n("This is a list of available KDE services which will " "be started on demand. They are only listed for convenience, as you " "cannot manipulate these services.")); lay->addWidget( gb ); QVBoxLayout *gblay = new QVBoxLayout( gb ); _lvLoD = new QTreeWidget( gb ); QStringList cols; cols.append( i18n("Service") ); cols.append( i18n("Status") ); cols.append( i18n("Description") ); _lvLoD->setHeaderLabels( cols ); _lvLoD->setAllColumnsShowFocus(true); _lvLoD->setRootIsDecorated( false ); _lvLoD->setSortingEnabled(true); _lvLoD->sortByColumn(OnDemandService, Qt::AscendingOrder); _lvLoD->header()->setStretchLastSection(true); gblay->addWidget( _lvLoD ); gb = new QGroupBox( i18n("Startup Services"), this ); gb->setWhatsThis( i18n("This shows all KDE services that can be loaded " "on Plasma startup. Checked services will be invoked on next startup. " "Be careful with deactivation of unknown services.")); lay->addWidget( gb ); gblay = new QVBoxLayout( gb ); _lvStartup = new QTreeWidget( gb ); cols.clear(); cols.append( i18n("Use") ); cols.append( i18n("Service") ); cols.append( i18n("Status") ); cols.append( i18n("Description") ); _lvStartup->setHeaderLabels( cols ); _lvStartup->setAllColumnsShowFocus(true); _lvStartup->setRootIsDecorated( false ); _lvStartup->setSortingEnabled(true); _lvStartup->sortByColumn(StartupService, Qt::AscendingOrder); _lvStartup->header()->setStretchLastSection(true); gblay->addWidget( _lvStartup ); QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal, gb); _pbStart = buttonBox->addButton( i18n("Start") , QDialogButtonBox::ActionRole ); _pbStop = buttonBox->addButton( i18n("Stop") , QDialogButtonBox::ActionRole ); gblay->addWidget( buttonBox ); _pbStart->setEnabled( false ); _pbStop->setEnabled( false ); connect(_pbStart, &QPushButton::clicked, this, &KDEDConfig::slotStartService); connect(_pbStop, &QPushButton::clicked, this, &KDEDConfig::slotStopService); connect(_lvLoD, &QTreeWidget::itemSelectionChanged, this, &KDEDConfig::slotLodItemSelected); connect(_lvStartup, &QTreeWidget::itemSelectionChanged, this, &KDEDConfig::slotStartupItemSelected); connect(_lvStartup, &QTreeWidget::itemChanged, this, &KDEDConfig::slotItemChecked); } QString setModuleGroup(const KPluginMetaData &module) { return QStringLiteral("Module-%1").arg(module.pluginId()); } bool KDEDConfig::autoloadEnabled(KConfig *config, const KPluginMetaData &module) { KConfigGroup cg(config, setModuleGroup(module)); return cg.readEntry("autoload", true); } void KDEDConfig::setAutoloadEnabled(KConfig *config, const KPluginMetaData &module, bool b) { KConfigGroup cg(config, setModuleGroup(module)); return cg.writeEntry("autoload", b); } // This code was copied from kded.cpp // TODO: move this KCM to the KDED framework and share the code? static QVector availableModules() { QVector plugins = KPluginLoader::findPlugins(QStringLiteral("kf5/kded")); QSet moduleIds; foreach (const KPluginMetaData &md, plugins) { moduleIds.insert(md.pluginId()); } // also search for old .desktop based kded modules KPluginInfo::List oldStylePlugins = KPluginInfo::fromServices(KServiceTypeTrader::self()->query(QStringLiteral("KDEDModule"))); foreach (const KPluginInfo &info, oldStylePlugins) { if (moduleIds.contains(info.pluginName())) { qCWarning(KCM_KDED).nospace() << "kded module " << info.pluginName() << " has already been found using " "JSON metadata, please don't install the now unneeded .desktop file (" << info.entryPath() << ")."; } else { qCDebug(KCM_KDED).nospace() << "kded module " << info.pluginName() << " still uses .desktop files (" << info.entryPath() << "). Please port it to JSON metadata."; plugins.append(info.toMetaData()); } } return plugins; } // this code was copied from kded.cpp static bool isModuleLoadedOnDemand(const KPluginMetaData &module) { bool loadOnDemand = true; // use toVariant() since it could be string or bool in the json and QJsonObject does not convert QVariant p = module.rawData().value(QStringLiteral("X-KDE-Kded-load-on-demand")).toVariant(); if (p.isValid() && p.canConvert() && (p.toBool() == false)) { loadOnDemand = false; } return loadOnDemand; } void KDEDConfig::load() { KConfig kdedrc(QStringLiteral("kded5rc"), KConfig::NoGlobals); _lvStartup->clear(); _lvLoD->clear(); QTreeWidgetItem* treeitem = 0L; const auto modules = availableModules(); for (const KPluginMetaData &mod : modules) { QString servicePath = mod.metaDataFileName(); // autoload defaults to false if it is not found const bool autoload = mod.rawData().value(QStringLiteral("X-KDE-Kded-autoload")).toVariant().toBool(); - const QString dbusModuleName = mod.value(QStringLiteral("X-KDE-DBus-ModuleName")); + // keep estimating dbusModuleName in sync with KDEDModule (kdbusaddons) and kded (kded) + // currently (KF5) the module name in the D-Bus object path is set by the pluginId + const QString dbusModuleName = mod.pluginId(); qCDebug(KCM_KDED) << "reading kded info from" << servicePath << "autoload =" << autoload << "dbus module name =" << dbusModuleName; // The logic has to be identical to Kded::initModules. // They interpret X-KDE-Kded-autoload as false if not specified // X-KDE-Kded-load-on-demand as true if not specified if (autoload) { treeitem = new QTreeWidgetItem(); treeitem->setCheckState(StartupUse, autoloadEnabled(&kdedrc, mod) ? Qt::Checked : Qt::Unchecked); treeitem->setText(StartupService, mod.name()); treeitem->setText(StartupDescription, mod.description()); treeitem->setText(StartupStatus, NOT_RUNNING); - if (!dbusModuleName.isEmpty()) { - treeitem->setData(StartupService, LibraryRole, dbusModuleName); - } else { - qCWarning(KCM_KDED) << "X-KDE-DBUS-ModuleName not set for module " << mod.name() << "from file" << mod.metaDataFileName(); - treeitem->setData(StartupService, LibraryRole, mod.fileName()); - } + treeitem->setData(StartupService, LibraryRole, dbusModuleName); _lvStartup->addTopLevelItem(treeitem); } else if (isModuleLoadedOnDemand(mod)) { treeitem = new QTreeWidgetItem(); treeitem->setText(OnDemandService, mod.name() ); treeitem->setText(OnDemandDescription, mod.description()); treeitem->setText(OnDemandStatus, NOT_RUNNING); - if (!dbusModuleName.isEmpty()) { - treeitem->setData(OnDemandService, LibraryRole, dbusModuleName); - } else { - qCWarning(KCM_KDED) << "X-KDE-DBUS-ModuleName not set for module " << mod.name() << "from file" << mod.metaDataFileName(); - treeitem->setData(OnDemandService, LibraryRole, mod.fileName()); - } + treeitem->setData(OnDemandService, LibraryRole, dbusModuleName); _lvLoD->addTopLevelItem(treeitem); } else { qCWarning(KCM_KDED) << "kcmkded: Module " << mod.name() << "from file" << mod.metaDataFileName() << " not loaded on demand or startup! Skipping."; } } _lvStartup->resizeColumnToContents(StartupUse); _lvStartup->resizeColumnToContents(StartupService); _lvStartup->resizeColumnToContents(StartupStatus); _lvLoD->resizeColumnToContents(OnDemandService); _lvLoD->resizeColumnToContents(OnDemandStatus); getServiceStatus(); emit changed(false); } void KDEDConfig::save() { KConfig kdedrc(QStringLiteral("kded5rc"), KConfig::NoGlobals); const auto modules = availableModules(); for (const KPluginMetaData &mod : modules) { qCDebug(KCM_KDED) << "saving settings for kded module" << mod.pluginId(); // autoload defaults to false if it is not found const bool autoload = mod.rawData().value(QStringLiteral("X-KDE-Kded-autoload")).toVariant().toBool(); if (autoload) { const QString libraryName = mod.pluginId(); int count = _lvStartup->topLevelItemCount(); for(int i = 0; i < count; ++i) { QTreeWidgetItem *treeitem = _lvStartup->topLevelItem(i); if ( treeitem->data(StartupService, LibraryRole ).toString() == libraryName) { // we found a match, now compare and see what changed setAutoloadEnabled(&kdedrc, mod, treeitem->checkState( StartupUse ) == Qt::Checked); break; } } } } kdedrc.sync(); emit changed(false); QDBusInterface kdedInterface(QStringLiteral("org.kde.kded5"), QStringLiteral("/kded"), QStringLiteral("org.kde.kded5")); kdedInterface.call(QStringLiteral("reconfigure")); QTimer::singleShot(0, this, &KDEDConfig::slotServiceRunningToggled); } void KDEDConfig::defaults() { int count = _lvStartup->topLevelItemCount(); for( int i = 0; i < count; ++i ) { _lvStartup->topLevelItem( i )->setCheckState( StartupUse, Qt::Checked ); } getServiceStatus(); emit changed(true); } void KDEDConfig::getServiceStatus() { QStringList modules; QDBusInterface kdedInterface( QStringLiteral("org.kde.kded5"), QStringLiteral("/kded"), QStringLiteral("org.kde.kded5") ); QDBusReply reply = kdedInterface.call( QStringLiteral("loadedModules") ); if ( reply.isValid() ) { modules = reply.value(); } else { _lvLoD->setEnabled( false ); _lvStartup->setEnabled( false ); KMessageBox::error(this, i18n("Unable to contact KDED.")); return; } qCDebug(KCM_KDED) << "Loaded kded modules:" << modules; // Initialize int count = _lvLoD->topLevelItemCount(); for( int i = 0; i < count; ++i ) _lvLoD->topLevelItem( i )->setText( OnDemandStatus, NOT_RUNNING ); count = _lvStartup->topLevelItemCount(); for( int i = 0; i < count; ++i ) _lvStartup->topLevelItem( i )->setText( StartupStatus, NOT_RUNNING ); // Fill foreach( const QString& module, modules ) { bool found = false; count = _lvLoD->topLevelItemCount(); for( int i = 0; i < count; ++i ) { QTreeWidgetItem *treeitem = _lvLoD->topLevelItem( i ); if ( treeitem->data( OnDemandService, LibraryRole ).toString() == module ) { treeitem->setText( OnDemandStatus, RUNNING ); found = true; break; } } count = _lvStartup->topLevelItemCount(); for( int i = 0; i < count; ++i ) { QTreeWidgetItem *treeitem = _lvStartup->topLevelItem( i ); if ( treeitem->data( StartupService, LibraryRole ).toString() == module ) { treeitem->setText( StartupStatus, RUNNING ); found = true; break; } } if (!found) { qCDebug(KCM_KDED) << "Could not relate module " << module; #ifndef NDEBUG qCDebug(KCM_KDED) << "Candidates were:"; count = _lvLoD->topLevelItemCount(); for( int i = 0; i < count; ++i ) { QTreeWidgetItem *treeitem = _lvLoD->topLevelItem( i ); qCDebug(KCM_KDED) << treeitem->data( OnDemandService, LibraryRole ).toString(); } count = _lvStartup->topLevelItemCount(); for( int i = 0; i < count; ++i ) { QTreeWidgetItem *treeitem = _lvStartup->topLevelItem( i ); qCDebug(KCM_KDED) << treeitem->data( StartupService, LibraryRole ).toString(); } #endif } } } void KDEDConfig::slotReload() { QString current; if ( !_lvStartup->selectedItems().isEmpty() ) current = _lvStartup->selectedItems().at(0)->data( StartupService, LibraryRole ).toString(); load(); if ( !current.isEmpty() ) { int count = _lvStartup->topLevelItemCount(); for( int i = 0; i < count; ++i ) { QTreeWidgetItem *treeitem = _lvStartup->topLevelItem( i ); if ( treeitem->data( StartupService, LibraryRole ).toString() == current ) { _lvStartup->setCurrentItem( treeitem, 0, QItemSelectionModel::ClearAndSelect ); break; } } } } void KDEDConfig::slotStartupItemSelected() { if ( _lvStartup->selectedItems().isEmpty() ) { // Disable the buttons _pbStart->setEnabled( false ); _pbStop->setEnabled( false ); return; } // Deselect a currently selected element in the "load on demand" treeview _lvLoD->setCurrentItem(NULL, 0, QItemSelectionModel::Clear); QTreeWidgetItem *item = _lvStartup->selectedItems().at(0); if ( item->text(StartupStatus) == RUNNING ) { _pbStart->setEnabled( false ); _pbStop->setEnabled( true ); } else if ( item->text(StartupStatus) == NOT_RUNNING ) { _pbStart->setEnabled( true ); _pbStop->setEnabled( false ); } else // Error handling, better do nothing { _pbStart->setEnabled( false ); _pbStop->setEnabled( false ); } getServiceStatus(); } void KDEDConfig::slotLodItemSelected() { if ( _lvLoD->selectedItems().isEmpty() ) return; // Deselect a currently selected element in the "load on startup" treeview _lvStartup->setCurrentItem(NULL, 0, QItemSelectionModel::Clear); } void KDEDConfig::slotServiceRunningToggled() { getServiceStatus(); slotStartupItemSelected(); } void KDEDConfig::slotStartService() { QString service = _lvStartup->selectedItems().at(0)->data( StartupService, LibraryRole ).toString(); QDBusInterface kdedInterface( QStringLiteral("org.kde.kded5"), QStringLiteral("/kded"),QStringLiteral("org.kde.kded5") ); QDBusReply reply = kdedInterface.call( QStringLiteral("loadModule"), service ); if ( reply.isValid() ) { if ( reply.value() ) slotServiceRunningToggled(); else KMessageBox::error(this, "" + i18n("Unable to start server %1.", service) + ""); } else { KMessageBox::error(this, "" + i18n("Unable to start service %1.

Error: %2", service, reply.error().message()) + "
" ); } } void KDEDConfig::slotStopService() { QString service = _lvStartup->selectedItems().at(0)->data( StartupService, LibraryRole ).toString(); qCDebug(KCM_KDED) << "Stopping: " << service; QDBusInterface kdedInterface( QStringLiteral("org.kde.kded5"), QStringLiteral("/kded"), QStringLiteral("org.kde.kded5") ); QDBusReply reply = kdedInterface.call( QStringLiteral("unloadModule"), service ); if ( reply.isValid() ) { if ( reply.value() ) slotServiceRunningToggled(); else KMessageBox::error(this, "" + i18n("Unable to stop service %1.", service) + ""); } else { KMessageBox::error(this, "" + i18n("Unable to stop service %1.

Error: %2", service, reply.error().message()) + "
" ); } } void KDEDConfig::slotItemChecked(QTreeWidgetItem*, int column) { // We only listen to changes the user did. if (column==StartupUse) { emit changed(true); } } #include "kcmkded.moc"