You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebase/kcontrol/kcontrol/modules.cpp

346 lines
8.5 KiB

/*
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 <tqlabel.h>
#include <tqlayout.h>
#include <tqvbox.h>
#include <tdeapplication.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 <tdecmoduleloader.h>
#include "kcrootonly.h"
#include <X11/Xlib.h>
template class TQPtrList<ConfigModule>;
ConfigModule::ConfigModule(const KService::Ptr &s)
: TDECModuleInfo(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);
TDECModule *modWidget = 0;
if (run_as_root && isHiddenByDefault())
modWidget = new KCRootOnly(0, "root_only");
else
modWidget = TDECModuleLoader::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;
TDECModuleLoader::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
// tdecmshell 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("<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, TQT_SIGNAL( windowEmbedded(WId)), TQT_SLOT( embedded()));
// prepare the process to run the tdecmshell
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) == "tdecmshell")
{
cmd = TQString(cmd.remove(0,8)).stripWhiteSpace();
kdeshell = true;
}
// run the process
TQString tdesu = TDEStandardDirs::findExe("tdesu");
if (!tdesu.isEmpty())
{
_rootProcess = new TDEProcess;
*_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", "tdecmshell")).arg(cmd).arg(_embedWidget->winId()).arg(TDEGlobal::locale()->language());
}
else {
*_rootProcess << TQString("%1 --embed %2 --lang %3").arg(cmd).arg(_embedWidget->winId()).arg( TDEGlobal::locale()->language() );
}
connect(_rootProcess, TQT_SIGNAL(processExited(TDEProcess*)), this, TQT_SLOT(rootExited(TDEProcess*)));
if ( !_rootProcess->start(TDEProcess::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(TDEProcess *)
{
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 TDEAboutData *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<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;
}
TQPtrList<ConfigModule> ConfigModuleList::modules(const TQString &path)
{
Menu *menu = subMenus.find(path);
if (menu)
return menu->modules;
return TQPtrList<ConfigModule>();
}
TQStringList ConfigModuleList::submenus(const TQString &path)
{
Menu *menu = subMenus.find(path);
if (menu)
return menu->submenus;
return TQStringList();
}
TQString ConfigModuleList::findModule(ConfigModule *module)
{
TQDictIterator<Menu> it(subMenus);
Menu *menu;
for(;(menu = it.current());++it)
{
if (menu->modules.containsRef(module))
return it.currentKey();
}
return TQString::null;
}