/* Copyright (c) 1999 Matthias Hoelzer-Kluepfel 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 #include #include #include #include #include #include #include #include #include #include #include #include "modules.h" #include "modules.moc" #include "global.h" #include "proxywidget.h" #include #include "kcrootonly.h" #include template class TQPtrList; 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, TQT_SIGNAL(changed(bool)), this, TQT_SLOT(clientChanged(bool))); connect(_module, TQT_SIGNAL(closed()), this, TQT_SLOT(clientClosed())); connect(_module, TQT_SIGNAL(handbookRequest()), this, TQT_SIGNAL(handbookRequest())); connect(_module, TQT_SIGNAL(helpRequest()), this, TQT_SIGNAL(helpRequest())); connect(_module, TQT_SIGNAL(runAsRoot()), this, TQT_SLOT(runAsRoot())); return _module; } return 0; } void ConfigModule::deleteClient() { if (_embedWidget) XKillClient(tqt_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 TQVBoxLayout(_module->parentWidget()); _embedFrame = new TQVBox( _module->parentWidget() ); _embedFrame->setFrameStyle( TQFrame::Box | TQFrame::Raised ); TQPalette pal( red ); pal.setColor( TQColorGroup::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 TQWidgetStack(_embedFrame); _embedWidget = new KControlEmbed(_embedStack); _module->hide(); _embedFrame->show(); TQLabel *_busy = new TQLabel(i18n("Loading..."), _embedStack); _busy->setAlignment(AlignCenter); _busy->setTextFormat(RichText); _busy->setGeometry(0,0, _module->width(), _module->height()); _busy->show(); _embedStack->raiseWidget(_busy); connect(_embedWidget, TQT_SIGNAL( windowEmbedded(WId)), TQT_SLOT( embedded())); // prepare the process to run the kcmshell TQString cmd = service()->exec().stripWhiteSpace(); bool kdeshell = false; if (cmd.left(5) == "tdesu") { cmd = TQString(cmd.remove(0,5)).stripWhiteSpace(); // remove all tdesu switches while( cmd.length() > 1 && cmd[ 0 ] == '-' ) { int pos = cmd.find( ' ' ); cmd = TQString(cmd.remove( 0, pos )).stripWhiteSpace(); } } if (cmd.left(8) == "kcmshell") { cmd = TQString(cmd.remove(0,8)).stripWhiteSpace(); kdeshell = true; } // run the process TQString tdesu = KStandardDirs::findExe("tdesu"); if (!tdesu.isEmpty()) { _rootProcess = new KProcess; *_rootProcess << tdesu; *_rootProcess << "--nonewdcop"; // We have to disable the keep-password feature because // in that case the modules is started through tdesud and tdesu // 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 << TQString("%1 %2 --embed %3 --lang %4").arg(locate("exe", "kcmshell")).arg(cmd).arg(_embedWidget->winId()).arg(KGlobal::locale()->language()); } else { *_rootProcess << TQString("%1 --embed %2 --lang %3").arg(cmd).arg(_embedWidget->winId()).arg( KGlobal::locale()->language() ); } connect(_rootProcess, TQT_SIGNAL(processExited(KProcess*)), this, TQT_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(tqt_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 TQString &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(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; } TQPtrList ConfigModuleList::modules(const TQString &path) { Menu *menu = subMenus.find(path); if (menu) return menu->modules; return TQPtrList(); } TQStringList ConfigModuleList::submenus(const TQString &path) { Menu *menu = subMenus.find(path); if (menu) return menu->submenus; return TQStringList(); } TQString ConfigModuleList::findModule(ConfigModule *module) { TQDictIterator it(subMenus); Menu *menu; for(;(menu = it.current());++it) { if (menu->modules.containsRef(module)) return it.currentKey(); } return TQString::null; }