summaryrefslogtreecommitdiffstats
path: root/kcontrol/kcontrol/modules.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kcontrol/kcontrol/modules.cpp')
-rw-r--r--kcontrol/kcontrol/modules.cpp345
1 files changed, 345 insertions, 0 deletions
diff --git a/kcontrol/kcontrol/modules.cpp b/kcontrol/kcontrol/modules.cpp
new file mode 100644
index 000000000..b6d8a2693
--- /dev/null
+++ b/kcontrol/kcontrol/modules.cpp
@@ -0,0 +1,345 @@
+/*
+ Copyright (c) 1999 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
+
+ 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 <unistd.h>
+#include <sys/types.h>
+
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qvbox.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kservicegroup.h>
+#include <kprocess.h>
+#include <qxembed.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+
+#include "modules.h"
+#include "modules.moc"
+#include "global.h"
+#include "proxywidget.h"
+#include <kcmoduleloader.h>
+#include "kcrootonly.h"
+
+#include <X11/Xlib.h>
+
+
+template class QPtrList<ConfigModule>;
+
+
+ConfigModule::ConfigModule(const KService::Ptr &s)
+ : KCModuleInfo(s), _changed(false), _module(0), _embedWidget(0),
+ _rootProcess(0), _embedLayout(0), _embedFrame(0), _embedStack(0)
+{
+}
+
+ConfigModule::~ConfigModule()
+{
+ deleteClient();
+}
+
+ProxyWidget *ConfigModule::module()
+{
+ if (_module)
+ return _module;
+
+ bool run_as_root = needsRootPrivileges() && (getuid() != 0);
+
+ KCModule *modWidget = 0;
+
+ if (run_as_root && isHiddenByDefault())
+ modWidget = new KCRootOnly(0, "root_only");
+ else
+ modWidget = KCModuleLoader::loadModule(*this);
+
+ if (modWidget)
+ {
+
+ _module = new ProxyWidget(modWidget, moduleName(), "", run_as_root);
+ connect(_module, SIGNAL(changed(bool)), this, SLOT(clientChanged(bool)));
+ connect(_module, SIGNAL(closed()), this, SLOT(clientClosed()));
+ connect(_module, SIGNAL(handbookRequest()), this, SIGNAL(handbookRequest()));
+ connect(_module, SIGNAL(helpRequest()), this, SIGNAL(helpRequest()));
+ connect(_module, SIGNAL(runAsRoot()), this, SLOT(runAsRoot()));
+
+ return _module;
+ }
+
+ return 0;
+}
+
+void ConfigModule::deleteClient()
+{
+ if (_embedWidget)
+ XKillClient(qt_xdisplay(), _embedWidget->embeddedWinId());
+
+ delete _rootProcess;
+ _rootProcess = 0;
+
+ delete _embedWidget;
+ _embedWidget = 0;
+ delete _embedStack;
+ _embedStack = 0;
+ delete _embedFrame;
+ _embedFrame = 0;
+ kapp->syncX();
+
+ if(_module)
+ _module->close(true);
+ _module = 0;
+
+ delete _embedLayout;
+ _embedLayout = 0;
+
+ KCModuleLoader::unloadModule(*this);
+ _changed = false;
+}
+
+void ConfigModule::clientClosed()
+{
+ deleteClient();
+
+ emit changed(this);
+ emit childClosed();
+}
+
+
+void ConfigModule::clientChanged(bool state)
+{
+ setChanged(state);
+ emit changed(this);
+}
+
+
+void ConfigModule::runAsRoot()
+{
+ if (!_module)
+ return;
+
+ delete _rootProcess;
+ delete _embedWidget;
+ delete _embedLayout;
+ delete _embedStack;
+
+ // create an embed widget that will embed the
+ // kcmshell running as root
+ _embedLayout = new QVBoxLayout(_module->parentWidget());
+ _embedFrame = new QVBox( _module->parentWidget() );
+ _embedFrame->setFrameStyle( QFrame::Box | QFrame::Raised );
+ QPalette pal( red );
+ pal.setColor( QColorGroup::Background,
+ _module->parentWidget()->colorGroup().background() );
+ _embedFrame->setPalette( pal );
+ _embedFrame->setLineWidth( 2 );
+ _embedFrame->setMidLineWidth( 2 );
+ _embedLayout->addWidget(_embedFrame,1);
+ // cannot reparent anything else inside QXEmbed, so put the busy label separately
+ _embedStack = new QWidgetStack(_embedFrame);
+ _embedWidget = new KControlEmbed(_embedStack);
+ _module->hide();
+ _embedFrame->show();
+ QLabel *_busy = new QLabel(i18n("<big>Loading...</big>"), _embedStack);
+ _busy->setAlignment(AlignCenter);
+ _busy->setTextFormat(RichText);
+ _busy->setGeometry(0,0, _module->width(), _module->height());
+ _busy->show();
+ _embedStack->raiseWidget(_busy);
+ connect(_embedWidget, SIGNAL( windowEmbedded(WId)), SLOT( embedded()));
+
+ // prepare the process to run the kcmshell
+ QString cmd = service()->exec().stripWhiteSpace();
+ bool kdeshell = false;
+ if (cmd.left(5) == "kdesu")
+ {
+ cmd = cmd.remove(0,5).stripWhiteSpace();
+ // remove all kdesu switches
+ while( cmd.length() > 1 && cmd[ 0 ] == '-' )
+ {
+ int pos = cmd.find( ' ' );
+ cmd = cmd.remove( 0, pos ).stripWhiteSpace();
+ }
+ }
+
+ if (cmd.left(8) == "kcmshell")
+ {
+ cmd = cmd.remove(0,8).stripWhiteSpace();
+ kdeshell = true;
+ }
+
+ // run the process
+ QString kdesu = KStandardDirs::findExe("kdesu");
+ if (!kdesu.isEmpty())
+ {
+ _rootProcess = new KProcess;
+ *_rootProcess << kdesu;
+ *_rootProcess << "--nonewdcop";
+ // We have to disable the keep-password feature because
+ // in that case the modules is started through kdesud and kdesu
+ // returns before the module is running and that doesn't work.
+ // We also don't have a way to close the module in that case.
+ *_rootProcess << "--n"; // Don't keep password.
+ if (kdeshell) {
+ *_rootProcess << QString("%1 %2 --embed %3 --lang %4").arg(locate("exe", "kcmshell")).arg(cmd).arg(_embedWidget->winId()).arg(KGlobal::locale()->language());
+ }
+ else {
+ *_rootProcess << QString("%1 --embed %2 --lang %3").arg(cmd).arg(_embedWidget->winId()).arg( KGlobal::locale()->language() );
+ }
+
+ connect(_rootProcess, SIGNAL(processExited(KProcess*)), this, SLOT(rootExited(KProcess*)));
+
+ if ( !_rootProcess->start(KProcess::NotifyOnExit) )
+ {
+ delete _rootProcess;
+ _rootProcess = 0L;
+ }
+
+ return;
+ }
+
+ // clean up in case of failure
+ delete _embedStack;
+ _embedStack = 0;
+ delete _embedFrame;
+ _embedWidget = 0;
+ delete _embedLayout;
+ _embedLayout = 0;
+ _module->show();
+}
+
+
+void ConfigModule::rootExited(KProcess *)
+{
+ if (_embedWidget->embeddedWinId())
+ XDestroyWindow(qt_xdisplay(), _embedWidget->embeddedWinId());
+
+ delete _embedWidget;
+ _embedWidget = 0;
+
+ delete _rootProcess;
+ _rootProcess = 0;
+
+ delete _embedLayout;
+ _embedLayout = 0;
+
+ delete _module;
+ _module=0;
+
+ _changed = false;
+ emit changed(this);
+ emit childClosed();
+}
+
+void ConfigModule::embedded()
+{
+ _embedStack->raiseWidget(_embedWidget); // put it above the busy label
+}
+
+const KAboutData *ConfigModule::aboutData() const
+{
+ if (!_module) return 0;
+ return _module->aboutData();
+}
+
+
+ConfigModuleList::ConfigModuleList()
+{
+ setAutoDelete(true);
+ subMenus.setAutoDelete(true);
+}
+
+void ConfigModuleList::readDesktopEntries()
+{
+ readDesktopEntriesRecursive( KCGlobal::baseGroup() );
+}
+
+bool ConfigModuleList::readDesktopEntriesRecursive(const QString &path)
+{
+
+ KServiceGroup::Ptr group = KServiceGroup::group(path);
+
+ if (!group || !group->isValid()) return false;
+
+ KServiceGroup::List list = group->entries(true, true);
+
+ if( list.isEmpty() )
+ return false;
+
+ Menu *menu = new Menu;
+ subMenus.insert(path, menu);
+
+ for( KServiceGroup::List::ConstIterator it = list.begin();
+ it != list.end(); it++)
+ {
+ KSycocaEntry *p = (*it);
+ if (p->isType(KST_KService))
+ {
+ KService *s = static_cast<KService*>(p);
+ if (!kapp->authorizeControlModule(s->menuId()))
+ continue;
+
+ ConfigModule *module = new ConfigModule(s);
+ if (module->library().isEmpty())
+ {
+ delete module;
+ continue;
+ }
+
+ append(module);
+ menu->modules.append(module);
+ }
+ else if (p->isType(KST_KServiceGroup) &&
+ readDesktopEntriesRecursive(p->entryPath()) )
+ menu->submenus.append(p->entryPath());
+
+ }
+ return true;
+}
+
+QPtrList<ConfigModule> ConfigModuleList::modules(const QString &path)
+{
+ Menu *menu = subMenus.find(path);
+ if (menu)
+ return menu->modules;
+
+ return QPtrList<ConfigModule>();
+}
+
+QStringList ConfigModuleList::submenus(const QString &path)
+{
+ Menu *menu = subMenus.find(path);
+ if (menu)
+ return menu->submenus;
+
+ return QStringList();
+}
+
+QString ConfigModuleList::findModule(ConfigModule *module)
+{
+ QDictIterator<Menu> it(subMenus);
+ Menu *menu;
+ for(;(menu = it.current());++it)
+ {
+ if (menu->modules.containsRef(module))
+ return it.currentKey();
+ }
+ return QString::null;
+}