summaryrefslogtreecommitdiffstats
path: root/kicker/applets/naughty
diff options
context:
space:
mode:
Diffstat (limited to 'kicker/applets/naughty')
-rw-r--r--kicker/applets/naughty/Makefile.am30
-rw-r--r--kicker/applets/naughty/NaughtyApplet.cpp223
-rw-r--r--kicker/applets/naughty/NaughtyApplet.h76
-rw-r--r--kicker/applets/naughty/NaughtyConfigDialog.cpp98
-rw-r--r--kicker/applets/naughty/NaughtyConfigDialog.h58
-rw-r--r--kicker/applets/naughty/NaughtyProcessMonitor.cpp475
-rw-r--r--kicker/applets/naughty/NaughtyProcessMonitor.h76
-rw-r--r--kicker/applets/naughty/configure.in.in5
-rw-r--r--kicker/applets/naughty/naughty-happy.pngbin0 -> 457 bytes
-rw-r--r--kicker/applets/naughty/naughty-sad.pngbin0 -> 440 bytes
-rw-r--r--kicker/applets/naughty/naughtyapplet.desktop131
11 files changed, 1172 insertions, 0 deletions
diff --git a/kicker/applets/naughty/Makefile.am b/kicker/applets/naughty/Makefile.am
new file mode 100644
index 000000000..533df19c3
--- /dev/null
+++ b/kicker/applets/naughty/Makefile.am
@@ -0,0 +1,30 @@
+pic_DATA = naughty-happy.png naughty-sad.png
+picdir = $(kde_datadir)/naughtyapplet/pics
+
+INCLUDES = -I$(top_srcdir)/kicker/libkicker $(all_includes)
+
+kde_module_LTLIBRARIES = naughty_panelapplet.la
+
+naughty_panelapplet_la_SOURCES = \
+ NaughtyProcessMonitor.cpp \
+ NaughtyConfigDialog.cpp \
+ NaughtyApplet.cpp
+
+METASOURCES = AUTO
+
+noinst_HEADERS = \
+ NaughtyProcessMonitor.h \
+ NaughtyConfigDialog.h \
+ NaughtyApplet.h
+
+lnkdir = $(kde_datadir)/kicker/applets
+lnk_DATA = naughtyapplet.desktop
+
+EXTRA_DIST = $(lnk_DATA)
+
+naughty_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+naughty_panelapplet_la_LIBADD = ../../libkicker/libkickermain.la $(LIB_KDEUI) $(LIB_KVM)
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/naughtyapplet.pot
+
diff --git a/kicker/applets/naughty/NaughtyApplet.cpp b/kicker/applets/naughty/NaughtyApplet.cpp
new file mode 100644
index 000000000..c256aa36f
--- /dev/null
+++ b/kicker/applets/naughty/NaughtyApplet.cpp
@@ -0,0 +1,223 @@
+/*
+ Naughty applet - Runaway process monitor for the KDE panel
+
+ Copyright 2000 Rik Hemsley (rikkus) <rik@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 "NaughtyApplet.h"
+#include "NaughtyProcessMonitor.h"
+#include "NaughtyConfigDialog.h"
+
+#include <qmessagebox.h>
+#include <qtoolbutton.h>
+#include <qlayout.h>
+
+#include <kiconloader.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <kaboutapplication.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <kmessagebox.h>
+#include <qpushbutton.h>
+
+extern "C"
+{
+ KDE_EXPORT KPanelApplet* init(QWidget * parent, const QString & configFile)
+ {
+ KGlobal::locale()->insertCatalogue("naughtyapplet");
+
+ return new NaughtyApplet
+ (
+ configFile,
+ KPanelApplet::Normal,
+ KPanelApplet::About | KPanelApplet::Preferences,
+ parent,
+ "naughtyapplet"
+ );
+ }
+}
+
+NaughtyApplet::NaughtyApplet
+(
+ const QString & configFile,
+ Type t,
+ int actions,
+ QWidget * parent,
+ const char * name
+)
+ : KPanelApplet(configFile, t, actions, parent, name)
+{
+ KGlobal::iconLoader()->addAppDir("naughtyapplet");
+ setBackgroundOrigin( AncestorOrigin );
+
+ button_ = new SimpleButton(this);
+ button_->setFixedSize(20, 20);
+
+ QVBoxLayout * layout = new QVBoxLayout(this);
+ layout->addWidget(button_);
+
+ monitor_ = new NaughtyProcessMonitor(2, 20, this);
+
+ connect
+ (
+ button_, SIGNAL(clicked()),
+ this, SLOT(slotPreferences())
+ );
+
+ connect
+ (
+ monitor_, SIGNAL(runawayProcess(ulong, const QString &)),
+ this, SLOT(slotWarn(ulong, const QString &))
+ );
+
+ connect
+ (
+ monitor_, SIGNAL(load(uint)),
+ this, SLOT(slotLoad(uint))
+ );
+
+ loadSettings();
+
+ monitor_->start();
+}
+
+NaughtyApplet::~NaughtyApplet()
+{
+ KGlobal::locale()->removeCatalogue("naughtyapplet");
+}
+
+ void
+NaughtyApplet::slotWarn(ulong pid, const QString & name)
+{
+ if (ignoreList_.contains(name))
+ return;
+
+ QString s = i18n("A program called '%1' is slowing down the others "
+ "on your machine. It may have a bug that is causing "
+ "this, or it may just be busy.\n"
+ "Would you like to try to stop the program?");
+
+ int retval = KMessageBox::warningYesNo(this, s.arg(name), QString::null, i18n("Stop"), i18n("Keep Running"));
+
+ if (KMessageBox::Yes == retval)
+ monitor_->kill(pid);
+ else
+ {
+ s = i18n("In future, should busy programs called '%1' be ignored?");
+
+ retval = KMessageBox::questionYesNo(this, s.arg(name), QString::null, i18n("Ignore"), i18n("Do Not Ignore"));
+
+ if (KMessageBox::Yes == retval)
+ {
+ ignoreList_.append(name);
+ config()->writeEntry("IgnoreList", ignoreList_);
+ config()->sync();
+ }
+ }
+}
+
+ int
+NaughtyApplet::widthForHeight(int) const
+{
+ return 20;
+}
+
+ int
+NaughtyApplet::heightForWidth(int) const
+{
+ return 20;
+}
+
+ void
+NaughtyApplet::slotLoad(uint l)
+{
+ if (l > monitor_->triggerLevel())
+ button_->setPixmap(BarIcon("naughty-sad"));
+ else
+ button_->setPixmap(BarIcon("naughty-happy"));
+}
+
+ void
+NaughtyApplet::about()
+{
+ KAboutData about
+ (
+ "naughtyapplet",
+ I18N_NOOP("Naughty applet"),
+ "1.0",
+ I18N_NOOP("Runaway process catcher"),
+ KAboutData::License_GPL_V2,
+ "(C) 2000 Rik Hemsley (rikkus) <rik@kde.org>"
+ );
+
+ KAboutApplication a(&about, this);
+ a.exec();
+}
+
+ void
+NaughtyApplet::slotPreferences()
+{
+ preferences();
+}
+
+ void
+NaughtyApplet::preferences()
+{
+ NaughtyConfigDialog d
+ (
+ ignoreList_,
+ monitor_->interval(),
+ monitor_->triggerLevel(),
+ this
+ );
+
+ QDialog::DialogCode retval = QDialog::DialogCode(d.exec());
+
+ if (QDialog::Accepted == retval)
+ {
+ ignoreList_ = d.ignoreList();
+ monitor_->setInterval(d.updateInterval());
+ monitor_->setTriggerLevel(d.threshold());
+ saveSettings();
+ }
+}
+
+ void
+NaughtyApplet::loadSettings()
+{
+ ignoreList_ = config()->readListEntry("IgnoreList");
+ monitor_->setInterval(config()->readUnsignedNumEntry("UpdateInterval", 2));
+ monitor_->setTriggerLevel(config()->readUnsignedNumEntry("Threshold", 20));
+
+ // Add 'X' as a default.
+ if (ignoreList_.isEmpty() && !config()->hasKey("IgnoreList"))
+ ignoreList_.append("X");
+}
+
+ void
+NaughtyApplet::saveSettings()
+{
+ config()->writeEntry("IgnoreList", ignoreList_);
+ config()->writeEntry("UpdateInterval", monitor_->interval());
+ config()->writeEntry("Threshold", monitor_->triggerLevel());
+ config()->sync();
+}
+
+#include "NaughtyApplet.moc"
+
diff --git a/kicker/applets/naughty/NaughtyApplet.h b/kicker/applets/naughty/NaughtyApplet.h
new file mode 100644
index 000000000..00df51ec4
--- /dev/null
+++ b/kicker/applets/naughty/NaughtyApplet.h
@@ -0,0 +1,76 @@
+/*
+ Naughty applet - Runaway process monitor for the KDE panel
+
+ Copyright 2000 Rik Hemsley (rikkus) <rik@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.
+*/
+
+#ifndef NAUGHTY_H
+#define NAUGHTY_H
+
+#include <kpanelapplet.h>
+#include <qstringlist.h>
+
+#include "simplebutton.h"
+
+class NaughtyProcessMonitor;
+class QPushButton;
+
+class NaughtyApplet : public KPanelApplet
+{
+ Q_OBJECT
+
+ public:
+
+ NaughtyApplet
+ (
+ const QString & configFile,
+ Type t = Normal,
+ int actions = 0,
+ QWidget * parent = 0,
+ const char * name = 0
+ );
+
+ ~NaughtyApplet();
+
+ virtual int widthForHeight(int h) const;
+ virtual int heightForWidth(int w) const;
+
+ signals:
+
+ void layoutChanged();
+
+ protected slots:
+
+ void slotWarn(ulong pid, const QString & name);
+ void slotLoad(uint);
+ void slotPreferences();
+
+ protected:
+
+ virtual void about();
+ virtual void preferences();
+ virtual void loadSettings();
+ virtual void saveSettings();
+
+ private:
+
+ NaughtyProcessMonitor * monitor_;
+ SimpleButton * button_;
+ QStringList ignoreList_;
+};
+
+#endif
diff --git a/kicker/applets/naughty/NaughtyConfigDialog.cpp b/kicker/applets/naughty/NaughtyConfigDialog.cpp
new file mode 100644
index 000000000..e03a955cc
--- /dev/null
+++ b/kicker/applets/naughty/NaughtyConfigDialog.cpp
@@ -0,0 +1,98 @@
+/*
+ Naughty applet - Runaway process monitor for the KDE panel
+
+ Copyright 2000 Rik Hemsley (rikkus) <rik@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 <keditlistbox.h>
+#include <knuminput.h>
+#include <klocale.h>
+#include <qvbox.h>
+
+#include "NaughtyConfigDialog.h"
+#include "NaughtyConfigDialog.moc"
+
+NaughtyConfigDialog::NaughtyConfigDialog
+(
+ const QStringList & items,
+ uint updateInterval,
+ uint threshold,
+ QWidget * parent,
+ const char * name
+)
+ :
+ KDialogBase
+ (
+ parent,
+ name,
+ true,
+ i18n("Configuration"),
+ KDialogBase::Ok | KDialogBase::Cancel,
+ KDialogBase::Ok,
+ true
+ )
+{
+ QVBox * v = new QVBox(this);
+ setMainWidget(v);
+
+ kini_updateInterval_ = new KIntNumInput(updateInterval, v);
+ kini_threshold_ = new KIntNumInput(kini_updateInterval_, threshold, v);
+
+ kini_updateInterval_ ->setLabel(i18n("&Update interval:"));
+ kini_threshold_ ->setLabel(i18n("CPU &load threshold:"));
+
+ kini_updateInterval_ ->setRange(1, 20);
+ kini_threshold_ ->setRange(10, 1000);
+
+ listBox_ = new KEditListBox
+ (i18n("&Programs to Ignore"),
+ v,
+ "naughty config dialog ignore listbox",
+ false,
+ KEditListBox::Add | KEditListBox::Remove
+ );
+
+ listBox_->insertStringList(items);
+}
+
+NaughtyConfigDialog::~NaughtyConfigDialog()
+{
+}
+
+ uint
+NaughtyConfigDialog::updateInterval() const
+{
+ return uint(kini_updateInterval_->value());
+}
+
+ uint
+NaughtyConfigDialog::threshold() const
+{
+ return uint(kini_threshold_->value());
+}
+
+ QStringList
+NaughtyConfigDialog::ignoreList() const
+{
+ QStringList retval;
+
+ for (int i = 0; i < listBox_->count(); i++)
+ retval << listBox_->text(i);
+
+ return retval;
+}
+
diff --git a/kicker/applets/naughty/NaughtyConfigDialog.h b/kicker/applets/naughty/NaughtyConfigDialog.h
new file mode 100644
index 000000000..485cbf14f
--- /dev/null
+++ b/kicker/applets/naughty/NaughtyConfigDialog.h
@@ -0,0 +1,58 @@
+/*
+ Naughty applet - Runaway process monitor for the KDE panel
+
+ Copyright 2000 Rik Hemsley (rikkus) <rik@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.
+*/
+
+#ifndef NAUGHTY_CONFIG_DIALOG_H
+#define NAUGHTY_CONFIG_DIALOG_H
+
+#include <kdialogbase.h>
+
+class KEditListBox;
+class KIntNumInput;
+
+class NaughtyConfigDialog : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+
+ NaughtyConfigDialog
+ (
+ const QStringList & items,
+ uint interval,
+ uint threshold,
+ QWidget * parent = 0,
+ const char * name = 0
+ );
+
+ ~NaughtyConfigDialog();
+
+ QStringList ignoreList() const;
+ uint updateInterval() const;
+ uint threshold() const;
+
+ private:
+
+ KEditListBox * listBox_;
+
+ KIntNumInput * kini_updateInterval_;
+ KIntNumInput * kini_threshold_;
+};
+
+#endif
diff --git a/kicker/applets/naughty/NaughtyProcessMonitor.cpp b/kicker/applets/naughty/NaughtyProcessMonitor.cpp
new file mode 100644
index 000000000..f9d352902
--- /dev/null
+++ b/kicker/applets/naughty/NaughtyProcessMonitor.cpp
@@ -0,0 +1,475 @@
+/*
+ Naughty applet - Runaway process monitor for the KDE panel
+
+ Copyright 2000 Rik Hemsley (rikkus) <rik@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.
+*/
+
+/* OpenBSD support by Jean-Yves Burlett <jean-yves@burlett.org> */
+
+#ifdef __OpenBSD__
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+#include <sys/ucred.h>
+#include <sys/dkstat.h>
+#include <stdlib.h>
+#endif
+
+#include <sys/types.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <qfile.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+#include <qdir.h>
+#include <qtimer.h>
+#include <qmap.h>
+#include <qdatetime.h>
+
+#include <klocale.h>
+
+#include "NaughtyProcessMonitor.h"
+
+class NaughtyProcessMonitorPrivate
+{
+ public:
+
+ NaughtyProcessMonitorPrivate()
+ : interval_(0),
+ timer_(0),
+ oldLoad_(0),
+ triggerLevel_(0)
+ {
+ }
+
+ ~NaughtyProcessMonitorPrivate()
+ {
+ // Empty.
+ }
+
+ uint interval_;
+ QTimer * timer_;
+ QMap<ulong, uint> loadMap_;
+ QMap<ulong, uint> scoreMap_;
+#ifdef __OpenBSD__
+ QMap<ulong, uint> cacheLoadMap_;
+ QMap<ulong, uid_t> uidMap_;
+#endif
+ uint oldLoad_;
+ uint triggerLevel_;
+
+ private:
+
+ NaughtyProcessMonitorPrivate(const NaughtyProcessMonitorPrivate &);
+
+ NaughtyProcessMonitorPrivate & operator =
+ (const NaughtyProcessMonitorPrivate &);
+};
+
+NaughtyProcessMonitor::NaughtyProcessMonitor
+ (
+ uint interval,
+ uint triggerLevel,
+ QObject * parent,
+ const char * name
+ )
+ : QObject(parent, name)
+{
+ d = new NaughtyProcessMonitorPrivate;
+ d->interval_ = interval * 1000;
+ d->triggerLevel_ = triggerLevel;
+ d->timer_ = new QTimer(this);
+ connect(d->timer_, SIGNAL(timeout()), this, SLOT(slotTimeout()));
+}
+
+NaughtyProcessMonitor::~NaughtyProcessMonitor()
+{
+ delete d;
+}
+
+ void
+NaughtyProcessMonitor::start()
+{
+ d->timer_->start(d->interval_, true);
+}
+
+ void
+NaughtyProcessMonitor::stop()
+{
+ d->timer_->stop();
+}
+
+ uint
+NaughtyProcessMonitor::interval() const
+{
+ return d->interval_ / 1000;
+}
+
+ void
+NaughtyProcessMonitor::setInterval(uint i)
+{
+ stop();
+ d->interval_ = i * 1000;
+ start();
+}
+
+ uint
+NaughtyProcessMonitor::triggerLevel() const
+{
+ return d->triggerLevel_;
+}
+
+ void
+NaughtyProcessMonitor::setTriggerLevel(uint i)
+{
+ d->triggerLevel_ = i;
+}
+
+ void
+NaughtyProcessMonitor::slotTimeout()
+{
+ uint cpu = cpuLoad();
+
+ emit(load(cpu));
+
+ if (cpu > d->triggerLevel_ * (d->interval_ / 1000))
+ {
+ uint load;
+ QValueList<ulong> l(pidList());
+
+ for (QValueList<ulong>::ConstIterator it(l.begin()); it != l.end(); ++it)
+ if (getLoad(*it, load))
+ _process(*it, load);
+ }
+
+ d->timer_->start(d->interval_, true);
+}
+
+ void
+NaughtyProcessMonitor::_process(ulong pid, uint load)
+{
+ if (!d->loadMap_.contains(pid))
+ {
+ d->loadMap_.insert(pid, load);
+ return;
+ }
+
+ uint oldLoad = d->loadMap_[pid];
+ bool misbehaving = (load - oldLoad) > 40 * (d->interval_ / 1000);
+ bool wasMisbehaving = d->scoreMap_.contains(pid);
+
+ if (misbehaving)
+ if (wasMisbehaving)
+ {
+ d->scoreMap_.replace(pid, d->scoreMap_[pid] + 1);
+ if (canKill(pid))
+ emit(runawayProcess(pid, processName(pid)));
+ }
+ else
+ d->scoreMap_.insert(pid, 1);
+ else
+ if (wasMisbehaving)
+ d->scoreMap_.remove(pid);
+
+ d->loadMap_.replace(pid, load);
+}
+
+// Here begins the set of system-specific methods.
+
+ bool
+NaughtyProcessMonitor::canKill(ulong pid) const
+{
+#ifdef __linux__
+ QFile f("/proc/" + QString::number(pid) + "/status");
+
+ if (!f.open(IO_ReadOnly))
+ return false;
+
+ QTextStream t(&f);
+
+ QString s;
+
+ while (!t.atEnd() && s.left(4) != "Uid:")
+ s = t.readLine();
+
+ QStringList l(QStringList::split('\t', s));
+
+ uint a(l[1].toUInt());
+
+// What are these 3 fields for ? Would be nice if the Linux kernel docs
+// were complete, eh ?
+// uint b(l[2].toUInt());
+// uint c(l[3].toUInt());
+// uint d(l[4].toUInt());
+
+ return geteuid() == a;
+#elif defined(__OpenBSD__)
+ // simply check if entry exists in the uid map and use it
+ if (!d->uidMap_.contains(pid))
+ return false ;
+
+ return geteuid () == d->uidMap_[pid] ;
+#else
+ Q_UNUSED( pid );
+ return false;
+#endif
+}
+
+ QString
+NaughtyProcessMonitor::processName(ulong pid) const
+{
+#if defined(__linux__) || defined(__OpenBSD__)
+#ifdef __linux__
+ QFile f("/proc/" + QString::number(pid) + "/cmdline");
+
+ if (!f.open(IO_ReadOnly))
+ return i18n("Unknown");
+
+ QCString s;
+
+ while (true)
+ {
+ int c = f.getch();
+
+ // Stop at NUL
+ if (c == -1 || char(c) == '\0')
+ break;
+ else
+ s += char(c);
+ }
+
+ // Now strip 'kdeinit:' prefix.
+ QString unicode(QString::fromLocal8Bit(s));
+
+#elif defined(__OpenBSD__)
+ int mib[4] ;
+ size_t size ;
+ char **argv ;
+
+ // fetch argv for the process `pid'
+
+ mib[0] = CTL_KERN ;
+ mib[1] = KERN_PROC_ARGS ;
+ mib[2] = pid ;
+ mib[3] = KERN_PROC_ARGV ;
+
+ // we assume argv[0]'s size will be less than one page
+
+ size = getpagesize () ;
+ argv = (char **)calloc (size, sizeof (char)) ;
+ size-- ; // ensure argv is ended by 0
+ if (-1 == sysctl (mib, 4, argv, &size, NULL, 0)) {
+ free (argv) ;
+ return i18n("Unknown") ;
+ }
+
+ // Now strip 'kdeinit:' prefix.
+ QString unicode(QString::fromLocal8Bit(argv[0]));
+
+ free (argv) ;
+#endif
+
+ QStringList parts(QStringList::split(' ', unicode));
+
+ QString processName = parts[0] == "kdeinit:" ? parts[1] : parts[0];
+
+ int lastSlash = processName.findRev('/');
+
+ // Get basename, if there's a path.
+ if (-1 != lastSlash)
+ processName = processName.mid(lastSlash + 1);
+
+ return processName;
+
+#else
+ Q_UNUSED( pid );
+ return QString::null;
+#endif
+}
+
+ uint
+NaughtyProcessMonitor::cpuLoad() const
+{
+#ifdef __linux__
+ QFile f("/proc/stat");
+
+ if (!f.open(IO_ReadOnly))
+ return 0;
+
+ bool forgetThisOne = 0 == d->oldLoad_;
+
+ QTextStream t(&f);
+
+ QString s = t.readLine();
+
+ QStringList l(QStringList::split(' ', s));
+
+ uint user = l[1].toUInt();
+ uint sys = l[3].toUInt();
+
+ uint load = user + sys;
+ uint diff = load - d->oldLoad_;
+ d->oldLoad_ = load;
+
+ return (forgetThisOne ? 0 : diff);
+#elif defined(__OpenBSD__)
+ int mib[2] ;
+ long cp_time[CPUSTATES] ;
+ size_t size ;
+ uint load, diff ;
+ bool forgetThisOne = 0 == d->oldLoad_;
+
+ // fetch CPU time statistics
+
+ mib[0] = CTL_KERN ;
+ mib[1] = KERN_CPTIME ;
+
+ size = CPUSTATES * sizeof(long) ;
+
+ if (-1 == sysctl (mib, 2, cp_time, &size, NULL, 0))
+ return 0 ;
+
+ load = cp_time[CP_USER] + cp_time[CP_SYS] ;
+ diff = load - d->oldLoad_ ;
+ d->oldLoad_ = load ;
+
+ return (forgetThisOne ? 0 : diff);
+#else
+ return 0;
+#endif
+}
+
+ QValueList<ulong>
+NaughtyProcessMonitor::pidList() const
+{
+#ifdef __linux__
+ QStringList dl(QDir("/proc").entryList());
+
+ QValueList<ulong> pl;
+
+ for (QStringList::ConstIterator it(dl.begin()); it != dl.end(); ++it)
+ if (((*it)[0].isDigit()))
+ pl << (*it).toUInt();
+
+ return pl;
+#elif defined(__OpenBSD__)
+ int mib[3] ;
+ int nprocs = 0, nentries ;
+ size_t size ;
+ struct kinfo_proc *kp ;
+ int i ;
+ QValueList<ulong> l;
+
+ // fetch number of processes
+
+ mib[0] = CTL_KERN ;
+ mib[1] = KERN_NPROCS ;
+
+ if (-1 == sysctl (mib, 2, &nprocs, &size, NULL, 0))
+ return l ;
+
+ // magic size evaluation ripped from ps
+
+ size = (5 * nprocs * sizeof(struct kinfo_proc)) / 4 ;
+ kp = (struct kinfo_proc *)calloc (size, sizeof (char)) ;
+
+ // fetch process info
+
+ mib[0] = CTL_KERN ;
+ mib[1] = KERN_PROC ;
+ mib[2] = KERN_PROC_ALL ;
+
+ if (-1 == sysctl (mib, 3, kp, &size, NULL, 0)) {
+ free (kp) ;
+ return l ;
+ }
+
+ nentries = size / sizeof (struct kinfo_proc) ;
+
+ // time statistics and euid data are fetched only for processes in
+ // the pidList, so, instead of doing one sysctl per process for
+ // getLoad and canKill calls, simply cache the data we already have.
+
+ d->cacheLoadMap_.clear () ;
+ d->uidMap_.clear () ;
+ for (i = 0; i < nentries; i++) {
+ l << (unsigned long) kp[i].kp_proc.p_pid ;
+ d->cacheLoadMap_.insert (kp[i].kp_proc.p_pid,
+ (kp[i].kp_proc.p_uticks +
+ kp[i].kp_proc.p_sticks)) ;
+ d->uidMap_.insert (kp[i].kp_proc.p_pid,
+ kp[i].kp_eproc.e_ucred.cr_uid) ;
+ }
+
+ free (kp) ;
+
+ return l ;
+#else
+ QValueList<ulong> l;
+ return l;
+#endif
+}
+
+ bool
+NaughtyProcessMonitor::getLoad(ulong pid, uint & load) const
+{
+#ifdef __linux__
+ QFile f("/proc/" + QString::number(pid) + "/stat");
+
+ if (!f.open(IO_ReadOnly))
+ return false;
+
+ QTextStream t(&f);
+
+ QString line(t.readLine());
+
+ QStringList fields(QStringList::split(' ', line));
+
+ uint userTime (fields[13].toUInt());
+ uint sysTime (fields[14].toUInt());
+
+ load = userTime + sysTime;
+
+ return true;
+#elif defined(__OpenBSD__)
+ // use cache
+ if (!d->cacheLoadMap_.contains(pid))
+ return false ;
+
+ load = d->cacheLoadMap_[pid] ;
+ return true ;
+#else
+ Q_UNUSED( pid );
+ Q_UNUSED( load );
+ return false;
+#endif
+}
+
+ bool
+NaughtyProcessMonitor::kill(ulong pid) const
+{
+#if defined(__linux__) || defined(__OpenBSD__)
+ return 0 == ::kill(pid, SIGKILL);
+#else
+ Q_UNUSED( pid );
+ return false;
+#endif
+}
+
+#include "NaughtyProcessMonitor.moc"
diff --git a/kicker/applets/naughty/NaughtyProcessMonitor.h b/kicker/applets/naughty/NaughtyProcessMonitor.h
new file mode 100644
index 000000000..d7023dbd7
--- /dev/null
+++ b/kicker/applets/naughty/NaughtyProcessMonitor.h
@@ -0,0 +1,76 @@
+/*
+ Naughty applet - Runaway process monitor for the KDE panel
+
+ Copyright 2000 Rik Hemsley (rikkus) <rik@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.
+*/
+
+#ifndef NAUGHTY_PROCESS_MONITOR_H
+#define NAUGHTY_PROCESS_MONITOR_H
+
+#include <qobject.h>
+
+class NaughtyProcessMonitorPrivate;
+
+class NaughtyProcessMonitor : public QObject
+{
+ Q_OBJECT
+
+ public:
+
+ NaughtyProcessMonitor
+ (
+ uint interval,
+ uint triggerLevel,
+ QObject * parent = 0,
+ const char * name = 0
+ );
+
+ virtual ~NaughtyProcessMonitor();
+
+ void start();
+ void stop();
+
+ uint triggerLevel() const;
+ void setTriggerLevel(uint);
+ uint interval() const;
+ void setInterval(uint);
+
+ virtual uint cpuLoad() const;
+ virtual QValueList<ulong> pidList() const;
+ virtual bool getLoad(ulong pid, uint & load) const;
+ virtual QString processName(ulong pid) const;
+ virtual bool canKill(ulong pid) const;
+ virtual bool kill(ulong pid) const;
+
+ protected slots:
+
+ void slotTimeout();
+
+ signals:
+
+ void load(uint);
+ void runawayProcess(ulong pid, const QString & name);
+
+ private:
+
+ void _process(ulong pid, uint load);
+
+ NaughtyProcessMonitorPrivate * d;
+};
+
+#endif
+
diff --git a/kicker/applets/naughty/configure.in.in b/kicker/applets/naughty/configure.in.in
new file mode 100644
index 000000000..5847780f0
--- /dev/null
+++ b/kicker/applets/naughty/configure.in.in
@@ -0,0 +1,5 @@
+case "$host" in
+ *-*-freebsd*) LIB_KVM="-lkvm" ;;
+ *) LIB_KVM="" ;;
+esac
+AC_SUBST(LIB_KVM)
diff --git a/kicker/applets/naughty/naughty-happy.png b/kicker/applets/naughty/naughty-happy.png
new file mode 100644
index 000000000..3200b5270
--- /dev/null
+++ b/kicker/applets/naughty/naughty-happy.png
Binary files differ
diff --git a/kicker/applets/naughty/naughty-sad.png b/kicker/applets/naughty/naughty-sad.png
new file mode 100644
index 000000000..9b6541907
--- /dev/null
+++ b/kicker/applets/naughty/naughty-sad.png
Binary files differ
diff --git a/kicker/applets/naughty/naughtyapplet.desktop b/kicker/applets/naughty/naughtyapplet.desktop
new file mode 100644
index 000000000..f7cb6a35f
--- /dev/null
+++ b/kicker/applets/naughty/naughtyapplet.desktop
@@ -0,0 +1,131 @@
+[Desktop Entry]
+Type=Plugin
+Name=Runaway Process Catcher
+Name[af]=Weghardloop Proses Vanger
+Name[ar]=لاقط الإجرائات الهاربة
+Name[az]=İşıək Gedişat Yaxalayıcı
+Name[be]=Захоп завіснуўшых працэсаў
+Name[bg]=Неуправляеми процеси
+Name[bn]=অনিয়ন্ত্রিত প্রসেস প্রহরী
+Name[bs]=Hvatač odbjeglih procesa
+Name[ca]=Capturador de processos descontrolats
+Name[cs]=Odchytávač chybných procesů
+Name[csb]=Jachtôrz zagùbionëch procesów
+Name[cy]=Arhosydd Prosesau Di-derfyn
+Name[da]=Indfanger af løbsk-kørte processer
+Name[de]=Beenden unkontrollierter Prozesse
+Name[el]=Runaway Έλεγχος Διεργασιών
+Name[eo]=Kaptilo por eskapitaj procezoj
+Name[es]=Capturador de procesos desbocados
+Name[et]=Hanguvate protsesside püüdja
+Name[eu]=Ataza eroen harrapatzailea
+Name[fa]=گیرندۀ فرآیند فراری
+Name[fi]=Karanneiden prosessien kiinniottaja
+Name[fr]=Détecteur de processus fous
+Name[fy]=Processenmonitor
+Name[ga]=Sriantóir na bPróiseas Éalaitheach
+Name[gl]=Detector de Procesos Estragados
+Name[he]=תופס תהליכים נמלטים
+Name[hi]=रनअवे प्रॉसेस कैचर
+Name[hr]=Hvatač odbjeglih procesa
+Name[hu]=Folyamatszabályozó
+Name[is]=Ferlafangari
+Name[it]=Rilevatore di processi impazziti
+Name[ja]=手に負えないプロセスのキャッチャー
+Name[kk]=Жаңылыс процесстерді байқаушы
+Name[km]=ឧបករណ៍​ចាប់​យក​ដំណើរការ​ដែល​មិន​អាច​បញ្ជា​បាន
+Name[lo]=ດັກຈັບໂປຣເສດ
+Name[lt]=Pabėgusių procesų gaudyklė
+Name[lv]=Nevadāmu Procesu Savācējs
+Name[mk]=Фаќач на процеси бегалци
+Name[mn]=Удирдлагагүй процессуудыг төгсгөх
+Name[ms]=Penangkap Proses Luar Kawalan
+Name[mt]=Programm biex Jaqbad Proċessi Maħruba
+Name[nb]=Fanger løpske prosesser
+Name[nds]=Dörgahn Perzessen infangen
+Name[ne]=रन वे प्रोसेस क्याचर
+Name[nl]=Processenmonitor
+Name[nn]=Løpsk prosess-fangar
+Name[nso]=Moswari wa Tiragalo yeo e Tshabago
+Name[pa]=ਬੇਕਾਬੂ ਕਾਰਜ ਸ਼ਿਕਾਰੀ
+Name[pl]=Łowca zagubionych procesów
+Name[pt]=Colector de Processos em Fuga
+Name[pt_BR]=Captura de processos
+Name[ro]=Monitor de procese
+Name[ru]=Сторож сбойных процессов
+Name[rw]=Mufata Igikorwa Ntagenzura
+Name[se]=Báhtaran proseassaid dustejeaddji
+Name[sk]=Zachytenie chybných procesov
+Name[sl]=Prestrezovalnik pobeglih procesov
+Name[sr]=Хватач одбеглих процеса
+Name[sr@Latn]=Hvatač odbeglih procesa
+Name[sv]=Fånga bortsprungna processer
+Name[ta]=ஓடுபாதை செயல் பிடிப்பான்
+Name[tg]=Дастгиркунандаи протсессҳои қарорӣ
+Name[th]=ดักการจบโปรเซส
+Name[tr]=Sorunlu Süreç Yakalayıcı
+Name[tt]=Içqınğan Eşlänü Totqıç
+Name[uk]=Захоплювач процесів-дезертирів
+Name[ven]=TShitenwa tsha Catcher
+Name[vi]=Bắt Tiến trình Chạy trốn
+Name[wa]=Troûleu d' sot processus
+Name[zh_CN]=落跑进程捕捉器
+Name[zh_TW]=失控程式捕捉器
+Name[zu]=Umbambi wenqubo ebalekayo
+Comment=Detect and end broken processes which consume too much CPU time
+Comment[af]=Spoor stukkende prosesse op wat te veel CPU tyd opneem en stop hulle
+Comment[ar]=إكتشف و أنهي الإجرائات المقطوعة اللتي تستهلك الكثير من وقت تشغيل وحدة المعالجة المركزية
+Comment[be]=Вызначае і забівае зламаныя працэсы, якія выкарыстоўваюць працэсар надта моцна
+Comment[bg]=Намиране и прекратяване на процеси, които консумират твърде много ресурси
+Comment[bs]=Otkrij i završi neispravne procese koji zauzimaju previše CPU vremena
+Comment[ca]=Detecta i finalitza processos espatllats que consumeixen massa temps de CPU
+Comment[cs]=Zjištění a ukončení poškozených procesů ubírajících výkon
+Comment[csb]=Òdnajdiwô ë kùńczi niesprôwné procesë, jaczé brëkùją za wiele procesora
+Comment[da]=Detekterer og afslutter fejlagtige processer som bruger for meget processortid
+Comment[de]=Erkennen und Beenden fehlerhafter Prozesse, die zu viel Rechenzeit verbrauchen
+Comment[el]=Ανίχνευση και τερματισμός διεργασιών που καταναλώνουν μεγάλο χρόνο του επεξεργαστή
+Comment[eo]=Detekti kaj mortigi difektitajn procezojn konsumante tro da procezilo-tempon
+Comment[es]=Detectar procesos rotos que consumen demasiado tiempo del procesador
+Comment[et]=Liialt protsessoriaega kulutavate katkiste rakenduste avastamine ja nende töö lõpetamine
+Comment[eu]=Detektatu eta amaitu CPU gehiegi erabiltzen ari diren prozesuak
+Comment[fa]=آشکارسازی و پایان فرآیندهای قطع‌شده، که زمان خیلی زیاد واحد پردازش مرکزی را مصرف می‌کند.
+Comment[fi]=Tunnista ja lopeta rikkinäiset prosessit, jotka kuluttavat liikaa laskentatehoa.
+Comment[fr]=Détection et arrêt des programmes consommant trop de ressources du processeur
+Comment[fy]=Untdekke en stopje alle brutsen prosessen dy tefolle prosessortiid konsumearje
+Comment[gl]=Detecta e mata procesos estragados que consumen tempo de CPU
+Comment[he]=זהה וסגור תהליכים שצורכים יותר מדי זמן מעבד
+Comment[hr]=Otkrivanje i završavanje nedovršenih procesa koji troše previše procesorskog vremena
+Comment[hu]=A túl sok processzoridőt lefoglaló folyamatok meghatározása és bezárása
+Comment[is]=Uppgötvaðu og slökktu á rofnum ferlum sem taka of mikinn örgjörvatíma
+Comment[it]=Trova e termina i processi impazziti che consuma troppo processore
+Comment[ja]=CPU 時間を無駄に消費する壊れたプロセスを見つけて終了させる
+Comment[kk]=Проңессорды көп жұмсайтын процессарды табу және жою
+Comment[km]=រក និង​បញ្ចប់​ដំណើរការ​ខូច​ដែល​ប្រើ​ពេលវេលា CPU ច្រើន​ពេក
+Comment[lt]=Aptikti ir užbaigti sugadintus procesus, kurie suryja per daug CPU laiko
+Comment[mk]=Откривање и прекинување на нефункционални процеси што го трошат времето на процесорот
+Comment[nb]=Finn og avslutt løpske prosesser som tar for mye prosessorkraft
+Comment[nds]=Schaadhaftig Perzessen, de to veel Rekentiet bruukt, opdecken un beennen
+Comment[ne]=प्रसस्त CPU समय खपत गर्ने कमजोर प्रक्रिया पत्ता लगाउनुहोस् र अन्त्य गर्नुहोस्
+Comment[nl]=Detecteer en stop gebroken processen die teveel processortijd consumeren
+Comment[nn]=Finn og avslutt løpske prosessar som tek for myjke prosessorkraft.
+Comment[pl]=Wykrywa i kończy niesprawne procesy, które zużywają za dużo procesora
+Comment[pt]=Detectar e terminar os processos com problemas que estejam a consumir demasiado CPU
+Comment[pt_BR]=Detecta e finaliza processos quebrados que consomem muito tempo de CPU
+Comment[ro]=Detectează și termină procese defecte care consumă prea mult CPU
+Comment[ru]=Обнаружение и завершение процессов, требующим слишком много времени процессора
+Comment[se]=Gávnna jea heaittit reakčanan proseassaid mat geavahit menddo olu CPU-áiggi
+Comment[sk]=Zistenie a ukončenie procesov, ktoré spotrebúvajú priveľa času CPU
+Comment[sl]=Zaznavanje in pobijanje procesov, ki porabljajo preveč procesorskega časa
+Comment[sr]=Детектује и окончава покварене процесе који одузимају превише процесорског времена
+Comment[sr@Latn]=Detektuje i okončava pokvarene procese koji oduzimaju previše procesorskog vremena
+Comment[sv]=Detekterar och avslutar felaktiga processer som använder för mycket processortid
+Comment[th]=ตรวจจับและจบโปรเซสที่เสียหาย ซึ่งใช้เวลาของหน่วยประมวลผลมากเกินไป
+Comment[tr]=Sorunlu ve fazla işlemci gücü harcayan programları bulup yokeder
+Comment[uk]=Виявлення і припинення процесів, які споживають забагато часу процесора
+Comment[vi]=Phát hiện và ngừng các tiến trình gây lãng phí bộ vi xử lý
+Comment[wa]=Trove et arestêye les schetés processus k' eployèt trop di tins CPU
+Comment[zh_CN]=检测并结束占用太多 CPU 时间的进程
+Comment[zh_TW]=偵測並終結浪費多數 CPU 時間的破損程序
+Icon=runprocesscatcher
+X-KDE-Library=naughty_panelapplet
+X-KDE-UniqueApplet=true