diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8c850b99b..ea47957f6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,299 +1,14 @@
-find_package(Nepomuk REQUIRED)
-include (KDE4Defaults)
-include(NepomukMacros)
-
-include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${KDEBASE_WORKSPACE_SOURCE_DIR}/libs ${CMAKE_CURRENT_SOURCE_DIR}/.. ${KDE4_INCLUDES})
-if(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
- include_directories(${OPENGL_INCLUDE_DIR})
-endif(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
-
-add_subdirectory(tests)
-add_definitions(-DKDE_DEFAULT_DEBUG_AREA=1209)
-
-########### next target ###############
-
-set(plasmagik_SRCS
- packagemetadata.cpp
- packagestructure.cpp
- package.cpp
- )
-
-set(plasma_LIB_SRCS
- ${plasmagik_SRCS}
- abstractrunner.cpp
- animationdriver.cpp
- animator.cpp
- applet.cpp
- configloader.cpp
- containment.cpp
- context.cpp
- corona.cpp
- datacontainer.cpp
- dataengine.cpp
- dataenginemanager.cpp
- delegate.cpp
- dialog.cpp
- extender.cpp
- extenderitem.cpp
- paintutils.cpp
- framesvg.cpp
- plasma.cpp
- popupapplet.cpp
- private/applethandle.cpp
- private/datacontainer_p.cpp
- private/desktoptoolbox.cpp
- private/extenderapplet.cpp
- private/nativetabbar.cpp
- private/packages.cpp
- private/paneltoolbox.cpp
- private/style.cpp
- private/toolbox.cpp
- private/tooltip.cpp
- private/windowpreview.cpp
- querymatch.cpp
- runnercontext.cpp
- runnermanager.cpp
- scripting/appletscript.cpp
- scripting/dataenginescript.cpp
- scripting/runnerscript.cpp
- scripting/scriptengine.cpp
- scripting/uiloader.cpp
- service.cpp
- servicejob.cpp
- svg.cpp
- theme.cpp
- tooltipcontent.cpp
- tooltipmanager.cpp
- version.cpp
- view.cpp
- wallpaper.cpp
- widgets/checkbox.cpp
- widgets/combobox.cpp
- widgets/flashinglabel.cpp
- widgets/frame.cpp
- widgets/groupbox.cpp
- widgets/iconwidget.cpp
- widgets/label.cpp
- widgets/lineedit.cpp
- widgets/meter.cpp
- widgets/pushbutton.cpp
- widgets/radiobutton.cpp
- widgets/scrollbar.cpp
- widgets/signalplotter.cpp
- widgets/slider.cpp
- widgets/busywidget.cpp
- widgets/svgwidget.cpp
- widgets/tabbar.cpp
- widgets/treeview.cpp
- widgets/textedit.cpp
- widgets/webview.cpp
-)
-
-#NEPOMUK_GENERATE_FROM_ONTOLOGY(
-# nwc.nrl
-# ${metadata_test_BINARY_DIR}
-# TEST_HEADERS
-# TEST_SOURCES
-# TEST_INCLUDES
-#)
-
-if(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
-MESSAGE(STATUS "Adding support for OpenGL applets to libplasma")
-set(plasma_LIB_SRCS
- ${plasma_LIB_SRCS}
- glapplet.cpp)
-endif(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
-
-kde4_add_library(plasma SHARED ${plasma_LIB_SRCS})
-
-target_link_libraries(plasma ${KDE4_KIO_LIBS} ${KDE4_KFILE_LIBS} ${KDE4_KNEWSTUFF2_LIBS}
- ${QT_QTUITOOLS_LIBRARY} ${QT_QTWEBKIT_LIBRARY}
- ${KDE4_THREADWEAVER_LIBRARIES} ${KDE4_SOLID_LIBS} ${X11_LIBRARIES})
-if(DL_LIBRARY)
-target_link_libraries(plasma ${DL_LIBRARY})
-endif(DL_LIBRARY)
-
-if(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
- target_link_libraries(plasma ${QT_QTOPENGL_LIBRARY} ${OPENGL_gl_LIBRARY})
-endif(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
-
-set_target_properties(plasma PROPERTIES
- VERSION 3.0.0
- SOVERSION 3
- ${KDE4_DISABLE_PROPERTY_}LINK_INTERFACE_LIBRARIES "${KDE4_KDEUI_LIBS}"
- )
-
-install(TARGETS plasma ${INSTALL_TARGETS_DEFAULT_ARGS})
-
-
-########### install files ###############
-
-set(plasmagik_HEADERS
- packagemetadata.h
- packagestructure.h
- package.h
- )
-
-install(FILES ${plasmagik_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/plasma/ COMPONENT Devel)
-
-set(plasma_LIB_INCLUDES
- abstractrunner.h
- animationdriver.h
- animator.h
- applet.h
- configloader.h
- containment.h
- context.h
- corona.h
- datacontainer.h
- dataengine.h
- dataenginemanager.h
- delegate.h
- dialog.h
- extender.h
- extenderitem.h
- paintutils.h
- framesvg.h
- plasma.h
- plasma_export.h
- popupapplet.h
- querymatch.h
- runnercontext.h
- runnermanager.h
- service.h
- servicejob.h
- svg.h
- theme.h
- tooltipcontent.h
- tooltipmanager.h
- tooltipmanager.h
- version.h
- view.h
- wallpaper.h)
-
-if(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
-set(plasma_LIB_INCLUDES
- ${plasma_LIB_INCLUDES}
- glapplet.h)
-endif(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
-
-install(FILES
- ${plasma_LIB_INCLUDES}
- DESTINATION ${INCLUDE_INSTALL_DIR}/plasma COMPONENT Devel)
-
-install(FILES
- widgets/checkbox.h
- widgets/combobox.h
- widgets/flashinglabel.h
- widgets/frame.h
- widgets/groupbox.h
- widgets/iconwidget.h
- widgets/label.h
- widgets/lineedit.h
- widgets/meter.h
- widgets/pushbutton.h
- widgets/radiobutton.h
- widgets/scrollbar.h
- widgets/signalplotter.h
- widgets/slider.h
- widgets/busywidget.h
- widgets/svgwidget.h
- widgets/tabbar.h
- widgets/treeview.h
- widgets/textedit.h
- widgets/webview.h
- DESTINATION ${INCLUDE_INSTALL_DIR}/plasma/widgets COMPONENT Devel)
-
-install(FILES
- scripting/appletscript.h
- scripting/dataenginescript.h
- scripting/runnerscript.h
- scripting/scriptengine.h
- scripting/uiloader.h
- DESTINATION ${INCLUDE_INSTALL_DIR}/plasma/scripting COMPONENT Devel)
-
-
-install(FILES
-includes/AbstractRunner
-includes/AnimationDriver
-includes/Animator
-includes/Applet
-includes/AppletScript
-includes/CheckBox
-includes/ComboBox
-includes/ConfigLoader
-includes/Containment
-includes/Context
-includes/Corona
-includes/DataContainer
-includes/DataEngine
-includes/DataEngineManager
-includes/DataEngineScript
-includes/Delegate
-includes/Dialog
-includes/Extender
-includes/ExtenderItem
-includes/FlashingLabel
-includes/Frame
-includes/FrameSvg
-includes/GroupBox
-includes/IconWidget
-includes/Label
-includes/LineEdit
-includes/Meter
-includes/Package
-includes/PackageMetadata
-includes/PackageStructure
-includes/PaintUtils
-includes/Plasma
-includes/PopupApplet
-includes/PushButton
-includes/QueryMatch
-includes/RadioButton
-includes/RunnerContext
-includes/RunnerManager
-includes/RunnerScript
-includes/ScriptEngine
-includes/ScrollBar
-includes/Service
-includes/ServiceJob
-includes/SignalPlotter
-includes/Slider
-includes/BusyWidget
-includes/Svg
-includes/SvgWidget
-includes/TabBar
-includes/TextEdit
-includes/ToolTipManager
-includes/Theme
-includes/TreeView
-includes/UiLoader
-includes/View
-includes/Version
-includes/Wallpaper
-includes/WebView
-DESTINATION ${INCLUDE_INSTALL_DIR}/KDE/Plasma COMPONENT Devel)
-
-if(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
- install(FILES
- includes/GLApplet
- DESTINATION ${INCLUDE_INSTALL_DIR}/KDE/Plasma COMPONENT Devel)
-endif(QT_QTOPENGL_FOUND AND OPENGL_FOUND)
-
-install(FILES
- servicetypes/plasma-animator.desktop
- servicetypes/plasma-applet.desktop
- servicetypes/plasma-containment.desktop
- servicetypes/plasma-dataengine.desktop
- servicetypes/plasma-packagestructure.desktop
- servicetypes/plasma-runner.desktop
- servicetypes/plasma-scriptengine.desktop
- servicetypes/plasma-wallpaper.desktop
- DESTINATION ${SERVICETYPES_INSTALL_DIR})
-
-install(FILES
- servicetypes/plasma-applet-extenderapplet.desktop
- DESTINATION ${SERVICES_INSTALL_DIR})
-
-install(FILES scripting/plasmoids.knsrc DESTINATION ${CONFIG_INSTALL_DIR})
+add_subdirectory(kdm)
+add_subdirectory(solid)
+add_subdirectory(plasma)
+add_subdirectory(libplasmaclock)
+if(NOT WIN32)
+ add_subdirectory(taskmanager)
+ add_subdirectory(ksysguard)
+ add_subdirectory(kworkspace)
+endif(NOT WIN32)
+if(Nepomuk_FOUND)
+ add_subdirectory(nepomukquery)
+ add_subdirectory(nepomukqueryclient)
+endif(Nepomuk_FOUND)
diff --git a/Mainpage.dox b/Mainpage.dox
index 225e338fb..9e107d1ee 100644
--- a/Mainpage.dox
+++ b/Mainpage.dox
@@ -1,100 +1,16 @@
-/** @mainpage Plasma libraries
+/** @mainpage KDE Workspace Libraries
-libplasma is the core of the Plasma desktop. It provides a framework of graphical
-widgets (Plasma::Applet) that can be organised into managed groupings
-(Plasma::Containment), such as a desktop or panel. It also provides a data
-abstraction layer (Plasma::DataEngine) and a corresponding service interaction
-layer (Plasma::Service) to make implementing widgets easier and a
-system of callouts (Plasma::AbstractRunner) that provide responses to queries,
-from running an application to performing a quick calculation.
+Libraries for the KDE workspace.
+
+The following libraries are available:
+- libplasma, a library for implementing
+ %Plasma applets and data engines
+- libkworkspace, a library for
+ interacting with the workspace
-The Qt Graphics View
-framework and the KDE
-libraries provide the underpinning for libplasma. As a result, it should
-work anywhere that Qt and KDE do.
-
-Although libplasma is developed for the use of Plasma, the new desktop shell in
-KDE 4, it is general enough to be useful in other applications.
-Amarok is already using it for its context
-view, allowing for pluggable widgets to display and interact with the music
-collection, such as "current track" and "tag cloud" widgets.
-
-libplasma itself only provides a framework, and the widgets, containments,
-data engines and runners are all implemented as plugins. However, the framework
-is designed to make implementing these plugins as easy as possible, including
-providing scripting support. Also, infrastructure such as a dialog to install
-new widgets and even download them from the web (Plasma::AppletBrowser) is also
-included.
-
-Other important classes are:
-
- - Plasma::Corona: the canvas that containments are placed on
- - Plasma::View: a QWidget for displaying a containment
- - Plasma::Theme: provides theming support
- - Plasma::Animator: provides animations for things like elements appearing
- and disappearing
- - Plasma::Delegate: provides an item delegate for Qt's
- Model /
- View framework for menu items.
- - Plasma::ToolTipManager: allows widgets have (themed) tooltips displayed when the
- mouse is hovered over them
- - Plasma::Dialog: displays a themed application dialog
- - Plasma::Extender: provides detachable sections to Plasma::Applet
- - Plasma::GLApplet: provides an OpneGL-rendered Plasma::Applet
- - Plasma::PackageStructure: provides descriptions of packages containing plugins
- for libplasma
- - Plasma::PopupApplet: provides a simple way of implementing a Plasma::Applet
- consisting of an icon that shows a popup when clicked
- - Plasma::Svg and Plasma::FrameSvg: provides themable, cached SVGs
- - Plasma::Wallpaper: provides pluggable backgrounds for containments
- - Plasma::AppletScript, Plasma::DataEngineScript, Plasma::RunnerScript and
- Plasma::ScriptEngine: provide scripting interfaces for plugins
- - Various themed QGraphicsWidgets for use in creating a Plasma::Applet
-
-
-The
-Plasma tutorials
-on TechBase provide a good introduction to writing plugins, such as widgets and
-data engines, for libplasma-based applications.
-
-@authors
-Aaron Seigo \
-Alessandro Diaferia \
-Alex Merry \
-Alexander Wiedenbruch \
-Alexis Ménard \
-André Duffeck \
-Andrew Lake \
-Bertjan Broeksema \
-Chani Armitage \
-Davide Bettio \
-Dan Meltzer \
-Fredrik Höglund \
-Ivan Cukic \
-John Tapsell \
-Jordi Polo \
-Kevin Ottens \
-Montel Laurent \
-Marco Martin \
-Matt Broadstone \
-Petri Damsten \
-Rafael Fernández López \
-Riccardo Iaconelli \
-Richard J. Moore \
-Rob Scheepmaker \
-Robert Knight \
-Sebastian Kuegler \
-Siraj Razick \
-Zack Rusin \
-
-@maintainers
-Aaron Seigo \
-
-@licenses
-@lgpl
+In addition, two KDM plugins are provided.
*/
-// DOXYGEN_SET_PROJECT_NAME = libplasma
-// DOXYGEN_SET_RECURSIVE = YES
+// DOXYGEN_SET_PROJECT_NAME = Libraries
// vim:ts=4:sw=4:expandtab:filetype=doxygen
diff --git a/kdm/CMakeLists.txt b/kdm/CMakeLists.txt
new file mode 100644
index 000000000..e3aa78734
--- /dev/null
+++ b/kdm/CMakeLists.txt
@@ -0,0 +1,47 @@
+
+include_directories( ${KDEBASE_WORKSPACE_SOURCE_DIR}/kdm/kfrontend )
+
+########### next target ###############
+
+set(kgreet_classic_PART_SRCS kgreet_classic.cpp )
+
+
+kde4_add_plugin(kgreet_classic ${kgreet_classic_PART_SRCS})
+
+
+target_link_libraries(kgreet_classic ${KDE4_KDEUI_LIBS})
+
+install(TARGETS kgreet_classic DESTINATION ${PLUGIN_INSTALL_DIR} )
+
+
+########### next target ###############
+
+set(kgreet_winbind_PART_SRCS kgreet_winbind.cpp )
+
+
+kde4_add_plugin(kgreet_winbind ${kgreet_winbind_PART_SRCS})
+
+
+target_link_libraries(kgreet_winbind ${KDE4_KDEUI_LIBS})
+
+install(TARGETS kgreet_winbind DESTINATION ${PLUGIN_INSTALL_DIR} )
+
+########### next target ###############
+
+set(kgreet_generic_PART_SRCS kgreet_generic.cpp )
+
+
+kde4_add_plugin(kgreet_generic ${kgreet_generic_PART_SRCS})
+
+
+target_link_libraries(kgreet_generic ${KDE4_KDEUI_LIBS})
+
+install(TARGETS kgreet_generic DESTINATION ${PLUGIN_INSTALL_DIR} )
+
+
+
+
+
+########### install files ###############
+
+install( FILES kgreeterplugin.h DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel )
diff --git a/kdm/Messages.sh b/kdm/Messages.sh
new file mode 100644
index 000000000..be2077f45
--- /dev/null
+++ b/kdm/Messages.sh
@@ -0,0 +1,4 @@
+#! /usr/bin/env bash
+$XGETTEXT kgreet_classic.cpp -o $podir/kgreet_classic.pot
+$XGETTEXT kgreet_winbind.cpp -o $podir/kgreet_winbind.pot
+$XGETTEXT kgreet_generic.cpp -o $podir/kgreet_generic.pot
diff --git a/kdm/kgreet_classic.cpp b/kdm/kgreet_classic.cpp
new file mode 100644
index 000000000..fa0b9b86b
--- /dev/null
+++ b/kdm/kgreet_classic.cpp
@@ -0,0 +1,484 @@
+/*
+
+Conversation widget for kdm greeter
+
+Copyright (C) 1997, 1998, 2000 Steffen Hansen
+Copyright (C) 2000-2003 Oswald Buddenhagen
+
+
+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 "kgreet_classic.h"
+#include "themer/kdmthemer.h"
+#include "themer/kdmitem.h"
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+static int echoMode;
+
+class KDMPasswordEdit : public KLineEdit {
+public:
+ KDMPasswordEdit( QWidget *parent ) : KLineEdit( parent )
+ {
+ if (::echoMode == -1)
+ setPasswordMode(true);
+ else
+ setEchoMode( ::echoMode ? Password : NoEcho );
+ setContextMenuPolicy( Qt::NoContextMenu );
+ }
+};
+
+KClassicGreeter::KClassicGreeter( KGreeterPluginHandler *_handler,
+ QWidget *parent,
+ const QString &_fixedEntity,
+ Function _func, Context _ctx ) :
+ QObject(),
+ KGreeterPlugin( _handler ),
+ fixedUser( _fixedEntity ),
+ func( _func ),
+ ctx( _ctx ),
+ exp( -1 ),
+ pExp( -1 ),
+ running( false )
+{
+ QGridLayout *grid = 0;
+ int line = 0;
+
+ if (!_handler->gplugHasNode( "user-entry" ) ||
+ !_handler->gplugHasNode( "pw-entry" ))
+ {
+ parent = new QWidget( parent );
+ parent->setObjectName( "talker" );
+ widgetList << parent;
+ grid = new QGridLayout( parent );
+ grid->setMargin( 0 );
+ }
+
+ loginLabel = passwdLabel = passwd1Label = passwd2Label = 0;
+ loginEdit = 0;
+ passwdEdit = passwd1Edit = passwd2Edit = 0;
+ if (ctx == ExUnlock || ctx == ExChangeTok)
+ fixedUser = KUser().loginName();
+ if (func != ChAuthTok) {
+ if (fixedUser.isEmpty()) {
+ loginEdit = new KLineEdit( parent );
+ loginEdit->setContextMenuPolicy( Qt::NoContextMenu );
+ connect( loginEdit, SIGNAL(editingFinished()), SLOT(slotLoginLostFocus()) );
+ connect( loginEdit, SIGNAL(editingFinished()), SLOT(slotChanged()) );
+ connect( loginEdit, SIGNAL(textChanged( const QString & )), SLOT(slotChanged()) );
+ connect( loginEdit, SIGNAL(selectionChanged()), SLOT(slotChanged()) );
+ if (!grid) {
+ loginEdit->setObjectName( "user-entry" );
+ widgetList << loginEdit;
+ } else {
+ loginLabel = new QLabel( i18n("&Username:"), parent );
+ loginLabel->setBuddy( loginEdit );
+ grid->addWidget( loginLabel, line, 0 );
+ grid->addWidget( loginEdit, line++, 1 );
+ }
+ } else if (ctx != Login && ctx != Shutdown && grid) {
+ loginLabel = new QLabel( i18n("Username:"), parent );
+ grid->addWidget( loginLabel, line, 0 );
+ grid->addWidget( new QLabel( fixedUser, parent ), line++, 1 );
+ }
+ passwdEdit = new KDMPasswordEdit( parent );
+ connect( passwdEdit, SIGNAL(textChanged( const QString & )),
+ SLOT(slotChanged()) );
+ connect( passwdEdit, SIGNAL(editingFinished()), SLOT(slotChanged()) );
+ if (!grid) {
+ passwdEdit->setObjectName( "pw-entry" );
+ widgetList << passwdEdit;
+ } else {
+ passwdLabel = new QLabel( func == Authenticate ?
+ i18n("&Password:") :
+ i18n("Current &password:"),
+ parent );
+ passwdLabel->setBuddy( passwdEdit );
+ grid->addWidget( passwdLabel, line, 0 );
+ grid->addWidget( passwdEdit, line++, 1 );
+ }
+ if (loginEdit)
+ loginEdit->setFocus();
+ else
+ passwdEdit->setFocus();
+ }
+ if (func != Authenticate) {
+ passwd1Edit = new KDMPasswordEdit( parent );
+ passwd1Label = new QLabel( i18n("&New password:"), parent );
+ passwd1Label->setBuddy( passwd1Edit );
+ passwd2Edit = new KDMPasswordEdit( parent );
+ passwd2Label = new QLabel( i18n("Con&firm password:"), parent );
+ passwd2Label->setBuddy( passwd2Edit );
+ if (grid) {
+ grid->addWidget( passwd1Label, line, 0 );
+ grid->addWidget( passwd1Edit, line++, 1 );
+ grid->addWidget( passwd2Label, line, 0 );
+ grid->addWidget( passwd2Edit, line, 1 );
+ }
+ if (!passwdEdit)
+ passwd1Edit->setFocus();
+ }
+}
+
+// virtual
+KClassicGreeter::~KClassicGreeter()
+{
+ abort();
+ qDeleteAll( widgetList );
+}
+
+void // virtual
+KClassicGreeter::loadUsers( const QStringList &users )
+{
+ KCompletion *userNamesCompletion = new KCompletion;
+ userNamesCompletion->setItems( users );
+ loginEdit->setCompletionObject( userNamesCompletion );
+ loginEdit->setAutoDeleteCompletionObject( true );
+ loginEdit->setCompletionMode( KGlobalSettings::CompletionAuto );
+}
+
+void // virtual
+KClassicGreeter::presetEntity( const QString &entity, int field )
+{
+ loginEdit->setText( entity );
+ if (field == 1)
+ passwdEdit->setFocus();
+ else {
+ loginEdit->setFocus();
+ loginEdit->selectAll();
+ if (field == -1) {
+ passwdEdit->setText( " " );
+ passwdEdit->setEnabled( false );
+ authTok = false;
+ }
+ }
+ curUser = entity;
+}
+
+QString // virtual
+KClassicGreeter::getEntity() const
+{
+ return fixedUser.isEmpty() ? loginEdit->text() : fixedUser;
+}
+
+void // virtual
+KClassicGreeter::setUser( const QString &user )
+{
+ // assert( fixedUser.isEmpty() );
+ curUser = user;
+ loginEdit->setText( user );
+ passwdEdit->setFocus();
+ passwdEdit->selectAll();
+}
+
+void // virtual
+KClassicGreeter::setEnabled( bool enable )
+{
+ // assert( !passwd1Label );
+ // assert( func == Authenticate && ctx == Shutdown );
+// if (loginLabel)
+// loginLabel->setEnabled( enable );
+ passwdLabel->setEnabled( enable );
+ setActive( enable );
+ if (enable)
+ passwdEdit->setFocus();
+}
+
+void // private
+KClassicGreeter::returnData()
+{
+ switch (exp) {
+ case 0:
+ handler->gplugReturnText( (loginEdit ? loginEdit->text() :
+ fixedUser).toLocal8Bit(),
+ KGreeterPluginHandler::IsUser );
+ break;
+ case 1:
+ Q_ASSERT(passwdEdit);
+ handler->gplugReturnText( passwdEdit->text().toLocal8Bit() ,
+ KGreeterPluginHandler::IsPassword |
+ KGreeterPluginHandler::IsSecret );
+ break;
+ case 2:
+ Q_ASSERT(passwd1Edit);
+ handler->gplugReturnText( passwd1Edit->text().toLocal8Bit(),
+ KGreeterPluginHandler::IsSecret );
+ break;
+ default: // case 3:
+ Q_ASSERT(passwd2Edit);
+ handler->gplugReturnText( passwd2Edit->text().toLocal8Bit(),
+ KGreeterPluginHandler::IsNewPassword |
+ KGreeterPluginHandler::IsSecret );
+ break;
+ }
+}
+
+bool // virtual
+KClassicGreeter::textMessage( const char *text, bool err )
+{
+ if (!err &&
+ QString( text ).indexOf( QRegExp( "^Changing password for [^ ]+$" ) ) >= 0)
+ return true;
+ return false;
+}
+
+void // virtual
+KClassicGreeter::textPrompt( const char *prompt, bool echo, bool nonBlocking )
+{
+ pExp = exp;
+ if (echo)
+ exp = 0;
+ else if (!authTok)
+ exp = 1;
+ else {
+ QString pr( prompt );
+ if (pr.indexOf( QRegExp( "\\bpassword\\b", Qt::CaseInsensitive ) ) >= 0) {
+ if (pr.indexOf( QRegExp( "\\b(re-?(enter|type)|again|confirm|repeat)\\b",
+ Qt::CaseInsensitive ) ) >= 0)
+ exp = 3;
+ else if (pr.indexOf( QRegExp( "\\bnew\\b", Qt::CaseInsensitive ) ) >= 0)
+ exp = 2;
+ else { // QRegExp( "\\b(old|current)\\b", Qt::CaseInsensitive ) is too strict
+ handler->gplugReturnText( "",
+ KGreeterPluginHandler::IsOldPassword |
+ KGreeterPluginHandler::IsSecret );
+ return;
+ }
+ } else {
+ handler->gplugMsgBox( QMessageBox::Critical,
+ i18n("Unrecognized prompt \"%1\"",
+ prompt ) );
+ handler->gplugReturnText( 0, 0 );
+ exp = -1;
+ return;
+ }
+ }
+
+ if (pExp >= 0 && pExp >= exp) {
+ revive();
+ has = -1;
+ }
+
+ if (has >= exp || nonBlocking)
+ returnData();
+}
+
+bool // virtual
+KClassicGreeter::binaryPrompt( const char *, bool )
+{
+ // this simply cannot happen ... :}
+ return true;
+}
+
+void // virtual
+KClassicGreeter::start()
+{
+ authTok = !(passwdEdit && passwdEdit->isEnabled());
+ exp = has = -1;
+ running = true;
+}
+
+void // virtual
+KClassicGreeter::suspend()
+{
+}
+
+void // virtual
+KClassicGreeter::resume()
+{
+}
+
+void // virtual
+KClassicGreeter::next()
+{
+ // assert( running );
+ if (loginEdit && loginEdit->hasFocus()) {
+ passwdEdit->setFocus(); // will cancel running login if necessary
+ has = 0;
+ } else if (passwdEdit && passwdEdit->hasFocus()) {
+ if (passwd1Edit)
+ passwd1Edit->setFocus();
+ has = 1;
+ } else if (passwd1Edit) {
+ if (passwd1Edit->hasFocus()) {
+ passwd2Edit->setFocus();
+ has = 1; // sic!
+ } else
+ has = 3;
+ } else
+ has = 1;
+ if (exp < 0)
+ handler->gplugStart();
+ else if (has >= exp)
+ returnData();
+}
+
+void // virtual
+KClassicGreeter::abort()
+{
+ running = false;
+ if (exp >= 0) {
+ exp = -1;
+ handler->gplugReturnText( 0, 0 );
+ }
+}
+
+void // virtual
+KClassicGreeter::succeeded()
+{
+ // assert( running || timed_login );
+ if (!authTok) {
+ setActive( false );
+ if (passwd1Edit) {
+ authTok = true;
+ return;
+ }
+ } else
+ setActive2( false );
+ exp = -1;
+ running = false;
+}
+
+void // virtual
+KClassicGreeter::failed()
+{
+ // assert( running || timed_login );
+ setActive( false );
+ setActive2( false );
+ exp = -1;
+ running = false;
+}
+
+void // virtual
+KClassicGreeter::revive()
+{
+ // assert( !running );
+ setActive2( true );
+ if (authTok) {
+ passwd1Edit->clear();
+ passwd2Edit->clear();
+ passwd1Edit->setFocus();
+ } else {
+ passwdEdit->clear();
+ if (loginEdit && loginEdit->isEnabled())
+ passwdEdit->setEnabled( true );
+ else {
+ setActive( true );
+ if (loginEdit && loginEdit->text().isEmpty())
+ loginEdit->setFocus();
+ else
+ passwdEdit->setFocus();
+ }
+ }
+}
+
+void // virtual
+KClassicGreeter::clear()
+{
+ // assert( !running && !passwd1Edit );
+ passwdEdit->clear();
+ if (loginEdit) {
+ loginEdit->clear();
+ loginEdit->setFocus();
+ curUser.clear();
+ } else
+ passwdEdit->setFocus();
+}
+
+
+// private
+
+void
+KClassicGreeter::setActive( bool enable )
+{
+ if (loginEdit)
+ loginEdit->setEnabled( enable );
+ if (passwdEdit)
+ passwdEdit->setEnabled( enable );
+}
+
+void
+KClassicGreeter::setActive2( bool enable )
+{
+ if (passwd1Edit) {
+ passwd1Edit->setEnabled( enable );
+ passwd2Edit->setEnabled( enable );
+ }
+}
+
+void
+KClassicGreeter::slotLoginLostFocus()
+{
+ if (!running)
+ return;
+ if (exp > 0) {
+ if (curUser == loginEdit->text())
+ return;
+ exp = -1;
+ handler->gplugReturnText( 0, 0 );
+ }
+ curUser = loginEdit->text();
+ handler->gplugSetUser( curUser );
+}
+
+void
+KClassicGreeter::slotChanged()
+{
+ if (running)
+ handler->gplugChanged();
+}
+
+// factory
+
+static bool init( const QString &,
+ QVariant (*getConf)( void *, const char *, const QVariant & ),
+ void *ctx )
+{
+ echoMode = getConf( ctx, "EchoPasswd", QVariant( -1 ) ).toInt();
+ KGlobal::locale()->insertCatalog( "kgreet_classic" );
+ return true;
+}
+
+static void done( void )
+{
+ KGlobal::locale()->removeCatalog( "kgreet_classic" );
+}
+
+static KGreeterPlugin *
+create( KGreeterPluginHandler *handler,
+ QWidget *parent,
+ const QString &fixedEntity,
+ KGreeterPlugin::Function func,
+ KGreeterPlugin::Context ctx )
+{
+ return new KClassicGreeter( handler, parent, fixedEntity, func, ctx );
+}
+
+KDE_EXPORT KGreeterPluginInfo kgreeterplugin_info = {
+ I18N_NOOP2("@item:inmenu authentication method", "Username + password (classic)"), "classic",
+ KGreeterPluginInfo::Local | KGreeterPluginInfo::Presettable,
+ init, done, create
+};
+
+#include "kgreet_classic.moc"
diff --git a/kdm/kgreet_classic.h b/kdm/kgreet_classic.h
new file mode 100644
index 000000000..946a777e9
--- /dev/null
+++ b/kdm/kgreet_classic.h
@@ -0,0 +1,84 @@
+/*
+
+Conversation widget for kdm greeter
+
+Copyright (C) 1997, 1998 Steffen Hansen
+Copyright (C) 2000-2003 Oswald Buddenhagen
+
+
+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 KGREET_CLASSIC_H
+#define KGREET_CLASSIC_H
+
+#include "kgreeterplugin.h"
+
+#include
+
+class KLineEdit;
+class KSimpleConfig;
+class QLabel;
+
+class KClassicGreeter : public QObject, public KGreeterPlugin {
+ Q_OBJECT
+
+ public:
+ KClassicGreeter( KGreeterPluginHandler *handler,
+ QWidget *parent,
+ const QString &fixedEntitiy,
+ Function func, Context ctx );
+ ~KClassicGreeter();
+ virtual void loadUsers( const QStringList &users );
+ virtual void presetEntity( const QString &entity, int field );
+ virtual QString getEntity() const;
+ virtual void setUser( const QString &user );
+ virtual void setEnabled( bool on );
+ virtual bool textMessage( const char *message, bool error );
+ virtual void textPrompt( const char *prompt, bool echo, bool nonBlocking );
+ virtual bool binaryPrompt( const char *prompt, bool nonBlocking );
+ virtual void start();
+ virtual void suspend();
+ virtual void resume();
+ virtual void next();
+ virtual void abort();
+ virtual void succeeded();
+ virtual void failed();
+ virtual void revive();
+ virtual void clear();
+
+ public Q_SLOTS:
+ void slotLoginLostFocus();
+ void slotChanged();
+
+ private:
+ void setActive( bool enable );
+ void setActive2( bool enable );
+ void returnData();
+
+ QLabel *loginLabel, *passwdLabel, *passwd1Label, *passwd2Label;
+ KLineEdit *loginEdit;
+ KLineEdit *passwdEdit, *passwd1Edit, *passwd2Edit;
+ KSimpleConfig *stsFile;
+ QString fixedUser, curUser;
+ Function func;
+ Context ctx;
+ int exp, pExp, has;
+ bool running, authTok;
+};
+
+#endif /* KGREET_CLASSIC_H */
diff --git a/kdm/kgreet_generic.cpp b/kdm/kgreet_generic.cpp
new file mode 100644
index 000000000..f5b55e518
--- /dev/null
+++ b/kdm/kgreet_generic.cpp
@@ -0,0 +1,354 @@
+/*
+
+Conversation widget for kdm greeter
+
+Copyright (C) 2008 Dirk Mueller
+Copyright (C) 2008 Oswald Buddenhagen
+
+based on classic kdm greeter:
+
+ Copyright (C) 1997, 1998, 2000 Steffen Hansen
+ Copyright (C) 2000-2003 Oswald Buddenhagen
+
+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 "kgreet_generic.h"
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+extern KDE_EXPORT KGreeterPluginInfo kgreeterplugin_info; // defined at bottom
+
+static int echoMode;
+
+class KDMPasswordEdit : public KLineEdit {
+public:
+ KDMPasswordEdit( QWidget *parent = 0 ) : KLineEdit( parent )
+ {
+ if (::echoMode == -1)
+ setPasswordMode( true );
+ else
+ setEchoMode( ::echoMode ? Password : NoEcho );
+ setContextMenuPolicy( Qt::NoContextMenu );
+ }
+};
+
+KGenericGreeter::KGenericGreeter( KGreeterPluginHandler *_handler,
+ QWidget *parent,
+ const QString &_fixedEntity,
+ Function _func, Context _ctx ) :
+ QObject(),
+ KGreeterPlugin( _handler ),
+ m_lineEdit( 0 ),
+ fixedUser( _fixedEntity ),
+ func( _func ),
+ ctx( _ctx ),
+ exp( -1 ),
+ running( false )
+{
+ m_parentWidget = new QWidget( parent );
+ m_parentWidget->setObjectName( "talker" );
+ // XXX set some minimal size
+ widgetList << m_parentWidget;
+ m_grid = new QGridLayout( m_parentWidget );
+ m_grid->setMargin( 0 );
+
+ if (ctx == ExUnlock || ctx == ExChangeTok)
+ fixedUser = KUser().loginName();
+}
+
+// virtual
+KGenericGreeter::~KGenericGreeter()
+{
+ abort();
+ delete m_parentWidget;
+}
+
+void // virtual
+KGenericGreeter::loadUsers( const QStringList &users )
+{
+ m_users = users;
+}
+
+void // virtual
+KGenericGreeter::presetEntity( const QString &entity, int /* field */ )
+{
+ // assert( !running );
+ curUser = entity;
+}
+
+QString // virtual
+KGenericGreeter::getEntity() const
+{
+ return fixedUser.isEmpty() ? curUser : fixedUser;
+}
+
+void // virtual
+KGenericGreeter::setUser( const QString &user )
+{
+ // assert( running );
+ // assert( fixedUser.isEmpty() );
+ if (!(kgreeterplugin_info.flags & KGreeterPluginInfo::Presettable))
+ return; // Not interested in PAM telling us who logged in
+ if (exp) {
+ abort();
+ start();
+ }
+ curUser = user;
+ if (m_lineEdit) { // could be null if plugin is misconfigured
+ m_lineEdit->setText( user );
+ m_lineEdit->selectAll();
+ m_lineEdit->setFocus();
+ }
+}
+
+void // virtual
+KGenericGreeter::setEnabled( bool enable )
+{
+ // assert( func == Authenticate && ctx == Shutdown );
+ // XXX this is likely to bear some bogosity
+ foreach (QWidget *w, m_children)
+ w->setEnabled( enable );
+ if (enable && m_lineEdit)
+ m_lineEdit->setFocus();
+}
+
+bool // virtual
+KGenericGreeter::textMessage( const char *text, bool err )
+{
+ if (err)
+ return false;
+
+ if (m_infoMsgs.isEmpty())
+ revive();
+ QString qtext = QString::fromUtf8( text );
+ m_infoMsgs.append( qtext );
+ QLabel *label = new QLabel( qtext, m_parentWidget );
+ m_grid->addWidget( label, m_line++, 0, 1, 2 );
+ m_children.append( label );
+
+ return true;
+}
+
+void // virtual
+KGenericGreeter::textPrompt( const char *prompt, bool echo, bool /* nonBlocking */ )
+{
+ exp =
+ exp >= 0 ||
+ func != Authenticate ||
+ !(kgreeterplugin_info.flags & KGreeterPluginInfo::Presettable);
+
+ if (!exp && !fixedUser.isEmpty()) {
+ handler->gplugReturnText( fixedUser.toLocal8Bit(),
+ KGreeterPluginHandler::IsUser );
+ return;
+ }
+
+ if (m_infoMsgs.isEmpty())
+ revive();
+ else
+ m_infoMsgs.clear();
+
+ QLabel *label = new QLabel( QString::fromUtf8( prompt ).trimmed() );
+ m_grid->addWidget( label, m_line, 0 );
+ m_children.append( label );
+ m_echo = echo;
+ if (echo) {
+ m_lineEdit = new KLineEdit;
+ m_lineEdit->setContextMenuPolicy( Qt::NoContextMenu );
+ if (!exp) {
+ if (!m_users.isEmpty()) {
+ KCompletion *userNamesCompletion = new KCompletion;
+ userNamesCompletion->setItems( m_users );
+ m_lineEdit->setCompletionObject( userNamesCompletion );
+ m_lineEdit->setAutoDeleteCompletionObject( true );
+ m_lineEdit->setCompletionMode( KGlobalSettings::CompletionAuto );
+ }
+ if (!curUser.isEmpty()) {
+ m_lineEdit->setText( curUser );
+ m_lineEdit->selectAll();
+ connect( m_lineEdit, SIGNAL(selectionChanged()), SLOT(slotChanged()) );
+ }
+ connect( m_lineEdit, SIGNAL(editingFinished()), SLOT(slotLoginLostFocus()) );
+ }
+ connect( m_lineEdit, SIGNAL(editingFinished()), SLOT(slotChanged()) );
+ connect( m_lineEdit, SIGNAL(textChanged( const QString & )), SLOT(slotChanged()) );
+ } else {
+ m_lineEdit = new KDMPasswordEdit;
+ }
+ m_lineEdit->setMinimumWidth(
+ m_lineEdit->fontMetrics().width( "This is a long password" ) );
+ m_grid->addWidget( m_lineEdit, m_line, 1 );
+ m_children.append( m_lineEdit );
+ m_lineEdit->show();
+ m_lineEdit->setFocus();
+}
+
+bool // virtual
+KGenericGreeter::binaryPrompt( const char *, bool )
+{
+ // FIXME
+ return true;
+}
+
+void // virtual
+KGenericGreeter::start()
+{
+ exp = -1;
+ running = true;
+ handler->gplugStart();
+}
+
+void // virtual
+KGenericGreeter::suspend()
+{
+}
+
+void // virtual
+KGenericGreeter::resume()
+{
+}
+
+void // virtual
+KGenericGreeter::next()
+{
+ if (m_lineEdit) {
+ m_lineEdit->setEnabled( false );
+ QString text = m_lineEdit->text();
+ m_lineEdit = 0;
+ handler->gplugReturnText( text.toLocal8Bit(),
+ !m_echo ?
+ KGreeterPluginHandler::IsSecret :
+ !exp ?
+ KGreeterPluginHandler::IsUser : 0 );
+ }
+}
+
+void // virtual
+KGenericGreeter::abort()
+{
+ running = false;
+ if (exp >= 0) {
+ exp = -1;
+ handler->gplugReturnText( 0, 0 );
+ }
+}
+
+void // virtual
+KGenericGreeter::succeeded()
+{
+ failed(); // redefining terms :-D
+}
+
+void // virtual
+KGenericGreeter::failed()
+{
+ // assert( running || timed_login );
+ if (!m_infoMsgs.isEmpty()) {
+ QString text = "";
+ foreach (const QString &msg, m_infoMsgs)
+ text += "" + Qt::escape( msg ) + "
";
+ text += "";
+ revive();
+ handler->gplugMsgBox( QMessageBox::Information, text );
+ } else {
+ foreach (QWidget *w, m_children)
+ w->setEnabled( false );
+ }
+ exp = -1;
+ running = false;
+}
+
+void // virtual
+KGenericGreeter::revive()
+{
+ // assert( !running );
+ foreach (QWidget *w, m_children)
+ w->deleteLater();
+ m_children.clear();
+ m_infoMsgs.clear();
+ m_lineEdit = 0;
+ m_line = 0;
+}
+
+void // virtual
+KGenericGreeter::clear()
+{
+ // assert( !running && !passwd1Edit );
+ revive();
+ curUser = QString::null;
+}
+
+
+// private
+void
+KGenericGreeter::slotLoginLostFocus()
+{
+ if (curUser != m_lineEdit->text()) {
+ curUser = m_lineEdit->text();
+ handler->gplugSetUser( curUser );
+ }
+}
+
+void
+KGenericGreeter::slotChanged()
+{
+ handler->gplugChanged();
+}
+
+// factory
+static bool init( const QString &,
+ QVariant (*getConf)( void *, const char *, const QVariant & ),
+ void *ctx )
+{
+ echoMode = getConf( ctx, "EchoMode", QVariant( -1 ) ).toInt();
+ // Fielded entities are not supported per se.
+ // This implies that the first field is the presettable entity, if any.
+ if (getConf( ctx, "generic.Presettable", QVariant( false ) ).toBool())
+ kgreeterplugin_info.flags |= KGreeterPluginInfo::Presettable;
+ KGlobal::locale()->insertCatalog( "kgreet_generic" );
+ return true;
+}
+
+static void done( void )
+{
+ KGlobal::locale()->removeCatalog( "kgreet_generic" );
+}
+
+static KGreeterPlugin *
+create( KGreeterPluginHandler *handler,
+ QWidget *parent,
+ const QString &fixedEntity,
+ KGreeterPlugin::Function func,
+ KGreeterPlugin::Context ctx )
+{
+ return new KGenericGreeter( handler, parent, fixedEntity, func, ctx );
+}
+
+KDE_EXPORT KGreeterPluginInfo kgreeterplugin_info = {
+ I18N_NOOP2("@item:inmenu authentication method", "Generic"), "generic",
+ KGreeterPluginInfo::Local,
+ init, done, create
+};
+
+#include "kgreet_generic.moc"
diff --git a/kdm/kgreet_generic.h b/kdm/kgreet_generic.h
new file mode 100644
index 000000000..60c855f46
--- /dev/null
+++ b/kdm/kgreet_generic.h
@@ -0,0 +1,84 @@
+/*
+
+Conversation widget for kdm greeter
+
+Copyright (C) 2008 Dirk Mueller
+Copyright (C) 2008 Oswald Buddenhagen
+
+based on classic kdm greeter:
+
+ Copyright (C) 1997, 1998, 2000 Steffen Hansen
+ Copyright (C) 2000-2003 Oswald Buddenhagen
+
+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 KGREET_GENERIC_H
+#define KGREET_GENERIC_H
+
+#include "kgreeterplugin.h"
+
+#include
+
+class QGridLayout;
+class QWidget;
+class KLineEdit;
+
+class KGenericGreeter : public QObject, public KGreeterPlugin {
+ Q_OBJECT
+
+ public:
+ KGenericGreeter( KGreeterPluginHandler *handler,
+ QWidget *parent, const QString &fixedEntitiy,
+ Function func, Context ctx );
+ ~KGenericGreeter();
+ virtual void loadUsers( const QStringList &users );
+ virtual void presetEntity( const QString &entity, int field );
+ virtual QString getEntity() const;
+ virtual void setUser( const QString &user );
+ virtual void setEnabled( bool on );
+ virtual bool textMessage( const char *message, bool error );
+ virtual void textPrompt( const char *prompt, bool echo, bool nonBlocking );
+ virtual bool binaryPrompt( const char *prompt, bool nonBlocking );
+ virtual void start();
+ virtual void suspend();
+ virtual void resume();
+ virtual void next();
+ virtual void abort();
+ virtual void succeeded();
+ virtual void failed();
+ virtual void revive();
+ virtual void clear();
+
+ public slots:
+ void slotLoginLostFocus();
+ void slotChanged();
+
+ private:
+ QGridLayout *m_grid;
+ QList m_children;
+ KLineEdit *m_lineEdit;
+ QWidget *m_parentWidget;
+ QList m_infoMsgs;
+ QString fixedUser, curUser;
+ QStringList m_users;
+ Function func;
+ Context ctx;
+ int exp, m_line;
+ bool running, m_echo;
+};
+
+#endif /* KGREET_GENERIC_H */
diff --git a/kdm/kgreet_winbind.cpp b/kdm/kgreet_winbind.cpp
new file mode 100644
index 000000000..f7cf4c88a
--- /dev/null
+++ b/kdm/kgreet_winbind.cpp
@@ -0,0 +1,627 @@
+/*
+
+Conversation widget for kdm greeter
+
+Copyright (C) 1997, 1998, 2000 Steffen Hansen
+Copyright (C) 2000-2004 Oswald Buddenhagen
+
+
+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 "kgreet_winbind.h"
+#include "themer/kdmthemer.h"
+#include "themer/kdmitem.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+static int echoMode;
+
+class KDMPasswordEdit : public KLineEdit {
+public:
+ KDMPasswordEdit( QWidget *parent ) : KLineEdit( parent )
+ {
+ if (::echoMode == -1)
+ setPasswordMode(true);
+ else
+ setEchoMode( ::echoMode ? Password : NoEcho );
+ setContextMenuPolicy( Qt::NoContextMenu );
+ }
+};
+
+static char separator;
+static QStringList staticDomains;
+static QString defaultDomain;
+
+static void
+splitEntity( const QString &ent, QString &dom, QString &usr )
+{
+ int pos = ent.indexOf( separator );
+ if (pos < 0)
+ dom = "", usr = ent;
+ else
+ dom = ent.left( pos ), usr = ent.mid( pos + 1 );
+}
+
+KWinbindGreeter::KWinbindGreeter( KGreeterPluginHandler *_handler,
+ QWidget *parent,
+ const QString &_fixedEntity,
+ Function _func, Context _ctx ) :
+ QObject(),
+ KGreeterPlugin( _handler ),
+ func( _func ),
+ ctx( _ctx ),
+ exp( -1 ),
+ pExp( -1 ),
+ running( false )
+{
+ QGridLayout *grid = 0;
+
+ int line = 0;
+
+ if (!_handler->gplugHasNode( "domain-entry" ) ||
+ !_handler->gplugHasNode( "user-entry" ) ||
+ !_handler->gplugHasNode( "pw-entry" ))
+ {
+ parent = new QWidget( parent );
+ parent->setObjectName( "talker" );
+ widgetList << parent;
+ grid = new QGridLayout( parent );
+ grid->setMargin( 0 );
+ }
+
+ domainLabel = loginLabel = passwdLabel = passwd1Label = passwd2Label = 0;
+ domainCombo = 0;
+ loginEdit = 0;
+ passwdEdit = passwd1Edit = passwd2Edit = 0;
+ if (ctx == ExUnlock || ctx == ExChangeTok)
+ splitEntity( KUser().loginName(), fixedDomain, fixedUser );
+ else
+ splitEntity( _fixedEntity, fixedDomain, fixedUser );
+ if (func != ChAuthTok) {
+ if (fixedUser.isEmpty()) {
+ domainCombo = new KComboBox( parent );
+ connect( domainCombo, SIGNAL(activated( const QString & )),
+ SLOT(slotChangedDomain( const QString & )) );
+ connect( domainCombo, SIGNAL(activated( const QString & )),
+ SLOT(slotLoginLostFocus()) );
+ connect( domainCombo, SIGNAL(activated( const QString & )),
+ SLOT(slotChanged()) );
+ // should handle loss of focus
+ loginEdit = new KLineEdit( parent );
+ loginEdit->setContextMenuPolicy( Qt::NoContextMenu );
+
+ if (!grid) {
+ loginEdit->setObjectName( "user-entry" );
+ domainCombo->setObjectName( "domain-entry" );
+ widgetList << domainCombo << loginEdit;
+ } else {
+ domainLabel = new QLabel( i18n("&Domain:"), parent );
+ domainLabel->setBuddy( domainCombo );
+ loginLabel = new QLabel( i18n("&Username:"), parent );
+ loginLabel->setBuddy( loginEdit );
+ grid->addWidget( domainLabel, line, 0 );
+ grid->addWidget( domainCombo, line++, 1 );
+ grid->addWidget( loginLabel, line, 0 );
+ grid->addWidget( loginEdit, line++, 1 );
+ }
+ connect( loginEdit, SIGNAL(editingFinished()), SLOT(slotLoginLostFocus()) );
+ connect( loginEdit, SIGNAL(editingFinished()), SLOT(slotChanged()) );
+ connect( loginEdit, SIGNAL(textChanged( const QString & )), SLOT(slotChanged()) );
+ connect( loginEdit, SIGNAL(selectionChanged()), SLOT(slotChanged()) );
+ domainCombo->addItems( staticDomains );
+ QTimer::singleShot( 0, this, SLOT(slotStartDomainList()) );
+ } else if (ctx != Login && ctx != Shutdown && grid) {
+ domainLabel = new QLabel( i18n("Domain:"), parent );
+ grid->addWidget( domainLabel, line, 0 );
+ grid->addWidget( new QLabel( fixedDomain, parent ), line++, 1 );
+ loginLabel = new QLabel( i18n("Username:"), parent );
+ grid->addWidget( loginLabel, line, 0 );
+ grid->addWidget( new QLabel( fixedUser, parent ), line++, 1 );
+ }
+ passwdEdit = new KDMPasswordEdit( parent );
+ connect( passwdEdit, SIGNAL(textChanged( const QString & )),
+ SLOT(slotChanged()) );
+ connect( passwdEdit, SIGNAL(editingFinished()), SLOT(slotChanged()) );
+
+ if (!grid) {
+ passwdEdit->setObjectName( "pw-entry" );
+ widgetList << passwdEdit;
+ } else {
+ passwdLabel = new QLabel( func == Authenticate ?
+ i18n("&Password:") :
+ i18n("Current &password:"),
+ parent );
+ passwdLabel->setBuddy( passwdEdit );
+ grid->addWidget( passwdLabel, line, 0 );
+ grid->addWidget( passwdEdit, line++, 1 );
+ }
+
+ if (loginEdit)
+ loginEdit->setFocus();
+ else
+ passwdEdit->setFocus();
+ }
+ if (func != Authenticate) {
+ passwd1Edit = new KDMPasswordEdit( parent );
+ passwd1Label = new QLabel( i18n("&New password:"), parent );
+ passwd1Label->setBuddy( passwd1Edit );
+ passwd2Edit = new KDMPasswordEdit( parent );
+ passwd2Label = new QLabel( i18n("Con&firm password:"), parent );
+ passwd2Label->setBuddy( passwd2Edit );
+ if (grid) {
+ grid->addWidget( passwd1Label, line, 0 );
+ grid->addWidget( passwd1Edit, line++, 1 );
+ grid->addWidget( passwd2Label, line, 0 );
+ grid->addWidget( passwd2Edit, line, 1 );
+ }
+ if (!passwdEdit)
+ passwd1Edit->setFocus();
+ }
+}
+
+// virtual
+KWinbindGreeter::~KWinbindGreeter()
+{
+ abort();
+ qDeleteAll( widgetList );
+}
+
+void
+KWinbindGreeter::slotChangedDomain( const QString &dom )
+{
+ if (!loginEdit->completionObject())
+ return;
+ QStringList users;
+ if (dom == "") {
+ for (QStringList::ConstIterator it = allUsers.begin(); it != allUsers.end(); ++it)
+ if ((*it).indexOf( separator ) < 0)
+ users << *it;
+ } else {
+ QString st( dom + separator );
+ for (QStringList::ConstIterator it = allUsers.begin(); it != allUsers.end(); ++it)
+ if ((*it).startsWith( st ))
+ users << (*it).mid( st.length() );
+ }
+ loginEdit->completionObject()->setItems( users );
+}
+
+void // virtual
+KWinbindGreeter::loadUsers( const QStringList &users )
+{
+ allUsers = users;
+ KCompletion *userNamesCompletion = new KCompletion;
+ loginEdit->setCompletionObject( userNamesCompletion );
+ loginEdit->setAutoDeleteCompletionObject( true );
+ loginEdit->setCompletionMode( KGlobalSettings::CompletionAuto );
+ slotChangedDomain( defaultDomain );
+}
+
+void // virtual
+KWinbindGreeter::presetEntity( const QString &entity, int field )
+{
+ QString dom, usr;
+ splitEntity( entity, dom, usr );
+ domainCombo->setCurrentItem( dom, true );
+ slotChangedDomain( dom );
+ loginEdit->setText( usr );
+ if (field > 1)
+ passwdEdit->setFocus();
+ else if (field == 1 || field == -1) {
+ if (field == -1) {
+ passwdEdit->setText( " " );
+ passwdEdit->setEnabled( false );
+ authTok = false;
+ }
+ loginEdit->setFocus();
+ loginEdit->selectAll();
+ }
+ curUser = entity;
+}
+
+QString // virtual
+KWinbindGreeter::getEntity() const
+{
+ QString dom, usr;
+ if (fixedUser.isEmpty())
+ dom = domainCombo->currentText(), usr = loginEdit->text();
+ else
+ dom = fixedDomain, usr = fixedUser;
+ return dom == "" ? usr : dom + separator + usr;
+}
+
+void // virtual
+KWinbindGreeter::setUser( const QString &user )
+{
+ // assert (fixedUser.isEmpty());
+ curUser = user;
+ QString dom, usr;
+ splitEntity( user, dom, usr );
+ domainCombo->setCurrentItem( dom, true );
+ slotChangedDomain( dom );
+ loginEdit->setText( usr );
+ passwdEdit->setFocus();
+ passwdEdit->selectAll();
+}
+
+void // virtual
+KWinbindGreeter::setEnabled( bool enable )
+{
+ // assert( !passwd1Label );
+ // assert( func == Authenticate && ctx == Shutdown );
+// if (domainCombo)
+// domainCombo->setEnabled( enable );
+// if (loginLabel)
+// loginLabel->setEnabled( enable );
+ passwdLabel->setEnabled( enable );
+ setActive( enable );
+ if (enable)
+ passwdEdit->setFocus();
+}
+
+void // private
+KWinbindGreeter::returnData()
+{
+ switch (exp) {
+ case 0:
+ handler->gplugReturnText( getEntity().toLocal8Bit(),
+ KGreeterPluginHandler::IsUser );
+ break;
+ case 1:
+ handler->gplugReturnText( passwdEdit->text().toLocal8Bit(),
+ KGreeterPluginHandler::IsPassword |
+ KGreeterPluginHandler::IsSecret );
+ break;
+ case 2:
+ handler->gplugReturnText( passwd1Edit->text().toLocal8Bit(),
+ KGreeterPluginHandler::IsSecret );
+ break;
+ default: // case 3:
+ handler->gplugReturnText( passwd2Edit->text().toLocal8Bit(),
+ KGreeterPluginHandler::IsNewPassword |
+ KGreeterPluginHandler::IsSecret );
+ break;
+ }
+}
+
+bool // virtual
+KWinbindGreeter::textMessage( const char *text, bool err )
+{
+ if (!err &&
+ QString( text ).indexOf( QRegExp( "^Changing password for [^ ]+$" ) ) >= 0)
+ return true;
+ return false;
+}
+
+void // virtual
+KWinbindGreeter::textPrompt( const char *prompt, bool echo, bool nonBlocking )
+{
+ pExp = exp;
+ if (echo)
+ exp = 0;
+ else if (!authTok)
+ exp = 1;
+ else {
+ QString pr( prompt );
+ if (pr.indexOf( QRegExp( "\\b(old|current)\\b", Qt::CaseInsensitive ) ) >= 0) {
+ handler->gplugReturnText( "",
+ KGreeterPluginHandler::IsOldPassword |
+ KGreeterPluginHandler::IsSecret );
+ return;
+ } else if (pr.indexOf( QRegExp( "\\b(re-?(enter|type)|again|confirm|repeat)\\b",
+ Qt::CaseInsensitive ) ) >= 0)
+ exp = 3;
+ else if (pr.indexOf( QRegExp( "\\bnew\\b", Qt::CaseInsensitive ) ) >= 0)
+ exp = 2;
+ else {
+ handler->gplugMsgBox( QMessageBox::Critical,
+ i18n("Unrecognized prompt \"%1\"",
+ prompt ) );
+ handler->gplugReturnText( 0, 0 );
+ exp = -1;
+ return;
+ }
+ }
+
+ if (pExp >= 0 && pExp >= exp) {
+ revive();
+ has = -1;
+ }
+
+ if (has >= exp || nonBlocking)
+ returnData();
+}
+
+bool // virtual
+KWinbindGreeter::binaryPrompt( const char *, bool )
+{
+ // this simply cannot happen ... :}
+ return true;
+}
+
+void // virtual
+KWinbindGreeter::start()
+{
+ authTok = !(passwdEdit && passwdEdit->isEnabled());
+ exp = has = -1;
+ running = true;
+}
+
+void // virtual
+KWinbindGreeter::suspend()
+{
+}
+
+void // virtual
+KWinbindGreeter::resume()
+{
+}
+
+void // virtual
+KWinbindGreeter::next()
+{
+ // assert( running );
+ if (domainCombo && domainCombo->hasFocus())
+ loginEdit->setFocus();
+ else if (loginEdit && loginEdit->hasFocus()) {
+ passwdEdit->setFocus(); // will cancel running login if necessary
+ has = 0;
+ } else if (passwdEdit && passwdEdit->hasFocus()) {
+ if (passwd1Edit)
+ passwd1Edit->setFocus();
+ has = 1;
+ } else if (passwd1Edit) {
+ if (passwd1Edit->hasFocus()) {
+ passwd2Edit->setFocus();
+ has = 1; // sic!
+ } else
+ has = 3;
+ } else
+ has = 1;
+ if (exp < 0)
+ handler->gplugStart();
+ else if (has >= exp)
+ returnData();
+}
+
+void // virtual
+KWinbindGreeter::abort()
+{
+ running = false;
+ if (exp >= 0) {
+ exp = -1;
+ handler->gplugReturnText( 0, 0 );
+ }
+}
+
+void // virtual
+KWinbindGreeter::succeeded()
+{
+ // assert( running || timed_login );
+ if (!authTok) {
+ setActive( false );
+ if (passwd1Edit) {
+ authTok = true;
+ return;
+ }
+ } else
+ setActive2( false );
+ exp = -1;
+ running = false;
+}
+
+void // virtual
+KWinbindGreeter::failed()
+{
+ // assert( running || timed_login );
+ setActive( false );
+ setActive2( false );
+ exp = -1;
+ running = false;
+}
+
+void // virtual
+KWinbindGreeter::revive()
+{
+ // assert( !running );
+ setActive2( true );
+ if (authTok) {
+ passwd1Edit->clear();
+ passwd2Edit->clear();
+ passwd1Edit->setFocus();
+ } else {
+ passwdEdit->clear();
+ if (loginEdit && loginEdit->isEnabled())
+ passwdEdit->setEnabled( true );
+ else {
+ setActive( true );
+ if (loginEdit && loginEdit->text().isEmpty())
+ loginEdit->setFocus();
+ else
+ passwdEdit->setFocus();
+ }
+ }
+}
+
+void // virtual
+KWinbindGreeter::clear()
+{
+ // assert( !running && !passwd1Edit );
+ passwdEdit->clear();
+ if (loginEdit) {
+ domainCombo->setCurrentItem( defaultDomain );
+ slotChangedDomain( defaultDomain );
+ loginEdit->clear();
+ loginEdit->setFocus();
+ curUser.clear();
+ } else
+ passwdEdit->setFocus();
+}
+
+
+// private
+
+void
+KWinbindGreeter::setActive( bool enable )
+{
+ if (domainCombo)
+ domainCombo->setEnabled( enable );
+ if (loginEdit)
+ loginEdit->setEnabled( enable );
+ if (passwdEdit)
+ passwdEdit->setEnabled( enable );
+}
+
+void
+KWinbindGreeter::setActive2( bool enable )
+{
+ if (passwd1Edit) {
+ passwd1Edit->setEnabled( enable );
+ passwd2Edit->setEnabled( enable );
+ }
+}
+
+void
+KWinbindGreeter::slotLoginLostFocus()
+{
+ if (!running)
+ return;
+ QString ent( getEntity() );
+ if (exp > 0) {
+ if (curUser == ent)
+ return;
+ exp = -1;
+ handler->gplugReturnText( 0, 0 );
+ }
+ curUser = ent;
+ handler->gplugSetUser( curUser );
+}
+
+void
+KWinbindGreeter::slotChanged()
+{
+ if (running)
+ handler->gplugChanged();
+}
+
+void
+KWinbindGreeter::slotStartDomainList()
+{
+ m_domainLister = new KProcess( this );
+ (*m_domainLister) << "wbinfo" << "--own-domain" << "--trusted-domains";
+ m_domainLister->setOutputChannelMode( KProcess::OnlyStdoutChannel );
+ connect( m_domainLister, SIGNAL(finished( int, QProcess::ExitStatus )),
+ SLOT(slotEndDomainList()) );
+ m_domainLister->start();
+}
+
+void
+KWinbindGreeter::slotEndDomainList()
+{
+ QStringList domainList;
+
+ while (!m_domainLister->atEnd()) {
+ QString dom = m_domainLister->readLine();
+ dom.chop( 1 );
+ if (!staticDomains.contains( dom ))
+ domainList.append( dom );
+ }
+
+ delete m_domainLister;
+
+ for (int i = domainCombo->count(), min = staticDomains.count(); --i >= min; ) {
+ int dli = domainList.indexOf( domainCombo->itemText( i ) );
+ if (dli < 0) {
+ if (i == domainCombo->currentIndex())
+ domainCombo->setCurrentItem( defaultDomain );
+ domainCombo->removeItem( i );
+ } else
+ domainList.removeAt( dli );
+ }
+ domainCombo->addItems( domainList );
+
+ QTimer::singleShot( 5 * 1000, this, SLOT(slotStartDomainList()) );
+}
+
+// factory
+
+static bool init( const QString &,
+ QVariant (*getConf)( void *, const char *, const QVariant & ),
+ void *ctx )
+{
+ echoMode = getConf( ctx, "EchoPasswd", QVariant( -1 ) ).toInt();
+
+ staticDomains = getConf( ctx, "winbind.Domains", QVariant( "" ) ).toString().split( ':', QString::SkipEmptyParts );
+ if (!staticDomains.size())
+ staticDomains << "";
+ defaultDomain = getConf( ctx, "winbind.DefaultDomain", QVariant( staticDomains.first() ) ).toString();
+ QString sepstr = getConf( ctx, "winbind.Separator", QVariant( QString() ) ).toString();
+ if (sepstr.isNull()) {
+ FILE *sepfile = popen( "wbinfo --separator 2>/dev/null", "r" );
+ if (sepfile) {
+ QTextStream( sepfile ) >> sepstr;
+ if (pclose( sepfile ))
+ sepstr = "\\";
+ } else
+ sepstr = "\\";
+ }
+ separator = sepstr[0].toLatin1();
+
+ KGlobal::locale()->insertCatalog( "kgreet_winbind" );
+ return true;
+}
+
+static void done( void )
+{
+ KGlobal::locale()->removeCatalog( "kgreet_winbind" );
+ // avoid static deletion problems ... hopefully
+ staticDomains.clear();
+ defaultDomain.clear();
+}
+
+static KGreeterPlugin *
+create( KGreeterPluginHandler *handler,
+ QWidget *parent,
+ const QString &fixedEntity,
+ KGreeterPlugin::Function func,
+ KGreeterPlugin::Context ctx )
+{
+ return new KWinbindGreeter( handler, parent, fixedEntity, func, ctx );
+}
+
+KDE_EXPORT KGreeterPluginInfo kgreeterplugin_info = {
+ I18N_NOOP2("@item:inmenu authentication method", "Winbind / Samba"), "classic",
+ KGreeterPluginInfo::Local | KGreeterPluginInfo::Fielded | KGreeterPluginInfo::Presettable,
+ init, done, create
+};
+
+#include "kgreet_winbind.moc"
diff --git a/kdm/kgreet_winbind.h b/kdm/kgreet_winbind.h
new file mode 100644
index 000000000..f317fd83e
--- /dev/null
+++ b/kdm/kgreet_winbind.h
@@ -0,0 +1,94 @@
+/*
+
+Conversation widget for kdm greeter
+
+Copyright (C) 1997, 1998 Steffen Hansen
+Copyright (C) 2000-2003 Oswald Buddenhagen
+
+
+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 KGREET_WINBIND_H
+#define KGREET_WINBIND_H
+
+#include "kgreeterplugin.h"
+
+#include
+#include
+
+class KComboBox;
+class KLineEdit;
+class KSimpleConfig;
+class QLabel;
+class KProcess;
+
+class KWinbindGreeter : public QObject, public KGreeterPlugin {
+ Q_OBJECT
+
+ public:
+ KWinbindGreeter( KGreeterPluginHandler *handler,
+ QWidget *parent,
+ const QString &fixedEntitiy,
+ Function func, Context ctx );
+ ~KWinbindGreeter();
+ virtual void loadUsers( const QStringList &users );
+ virtual void presetEntity( const QString &entity, int field );
+ virtual QString getEntity() const;
+ virtual void setUser( const QString &user );
+ virtual void setEnabled( bool on );
+ virtual bool textMessage( const char *message, bool error );
+ virtual void textPrompt( const char *prompt, bool echo, bool nonBlocking );
+ virtual bool binaryPrompt( const char *prompt, bool nonBlocking );
+ virtual void start();
+ virtual void suspend();
+ virtual void resume();
+ virtual void next();
+ virtual void abort();
+ virtual void succeeded();
+ virtual void failed();
+ virtual void revive();
+ virtual void clear();
+
+ public Q_SLOTS:
+ void slotLoginLostFocus();
+ void slotChangedDomain( const QString &dom );
+ void slotChanged();
+ void slotStartDomainList();
+ void slotEndDomainList();
+
+ private:
+ void setActive( bool enable );
+ void setActive2( bool enable );
+ void returnData();
+
+ QLabel *domainLabel, *loginLabel, *passwdLabel, *passwd1Label, *passwd2Label;
+ KComboBox *domainCombo;
+ KLineEdit *loginEdit;
+ KLineEdit *passwdEdit, *passwd1Edit, *passwd2Edit;
+ KSimpleConfig *stsFile;
+ QString fixedDomain, fixedUser, curUser;
+ QStringList allUsers;
+ KProcess* m_domainLister;
+
+ Function func;
+ Context ctx;
+ int exp, pExp, has;
+ bool running, authTok;
+};
+
+#endif /* KGREET_WINBIND_H */
diff --git a/kdm/kgreeterplugin.h b/kdm/kgreeterplugin.h
new file mode 100644
index 000000000..9aada349d
--- /dev/null
+++ b/kdm/kgreeterplugin.h
@@ -0,0 +1,410 @@
+/*
+
+ Authentication method specific conversation plugin for KDE's greeter widgets
+
+ Copyright (C) 2003 Oswald Buddenhagen
+ Copyright (C) 2003 Fabian Kaiser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KGREETERPLUGIN_H
+#define KGREETERPLUGIN_H
+
+#include
+#include
+#include
+
+class QWidget;
+
+class KGreeterPluginHandler {
+public:
+ virtual ~KGreeterPluginHandler() {}
+ /* keep in sync with V_IS_* */
+ enum { IsSecret = 1, IsUser = 2, IsPassword = 4, IsOldPassword = 8,
+ IsNewPassword = 16 };
+ /**
+ * Reply to textPrompt().
+ * @param text text to return to core; null to abort auth cycle
+ * @param tag zero or one of Is*
+ */
+ virtual void gplugReturnText( const char *text, int tag ) = 0;
+ /**
+ * Reply to binaryPrompt().
+ * @param data data in pam_client format to return to the core;
+ * null to abort auth cycle
+ */
+ virtual void gplugReturnBinary( const char *data ) = 0;
+ /**
+ * Tell the greeter who is logging in.
+ * Call this preferably before gplugStart, as otherwise the .dmrc
+ * load will be delayed. Don't call at all if your plugin doesn't
+ * have the Local flag set. Call only for internally generated
+ * user changes.
+ * @param user the user logging in
+ */
+ virtual void gplugSetUser( const QString &user ) = 0;
+ /**
+ * Start processing.
+ */
+ virtual void gplugStart() = 0;
+ /**
+ * This should be called each time the talker changes in any way from the
+ * pristine state after an authentication cycle starts, so the greeter
+ * knows it must reset the fields after some time of inactivity.
+ */
+ virtual void gplugChanged() = 0;
+ /**
+ * Plugins that expect user input from a different device than the mouse or
+ * keyboard must call this when user activity is detected to prevent the
+ * greeter from resetting/going away. Events should be compressed to no
+ * more than ten per second; one every five seconds is actually enough.
+ * Events should be actual changes to the input fields, not random motion.
+ */
+ virtual void gplugActivity() = 0;
+ /**
+ * Show a message box on behalf of the talker.
+ * @param type message severity
+ * @param text message text
+ */
+ virtual void gplugMsgBox( QMessageBox::Icon type, const QString &text ) = 0;
+ /**
+ * Determine if the named widget is welcomed.
+ * @param id the widget name
+ */
+ virtual bool gplugHasNode( const QString &id ) = 0;
+};
+
+/**
+ * Abstract base class for conversation plugins ("talkers") to be used with
+ * KDM, kdesktop_lock, etc.
+ * The authentication method used by a particular instance of a plugin
+ * may be configurable, but the instance must handle exactly one method,
+ * i.e., info->method must be determined at the latest at init() time.
+ */
+class KGreeterPlugin {
+public:
+ KGreeterPlugin( KGreeterPluginHandler *h ) : handler( h ) {}
+ virtual ~KGreeterPlugin() {}
+
+ /**
+ * Variations of the talker:
+ * - Authenticate: authentication
+ * - AuthChAuthTok: authentication and password change
+ * - ChAuthTok: password change
+ */
+ enum Function { Authenticate, AuthChAuthTok, ChAuthTok };
+
+ /**
+ * Contexts the talker can be used in:
+ * - Login: kdm login dialog
+ * - Shutdown: kdm shutdown dialog
+ * - Unlock: kdm unlock dialog (TODO)
+ * - ChangeTok: kdm password change dialog (TODO)
+ * - ExUnlock: kdesktop_lock unlock dialog
+ * - ExChangeTok: kdepasswd password change dialog (TODO)
+ *
+ * The Ex* contexts exist within a running session; the talker must know
+ * how to obtain the currently logged in user (+ domain/realm, etc.)
+ * itself (i.e., fixedEntity will be null). The non-Ex variants will have
+ * a fixedEntity passed in.
+ */
+ enum Context { Login, Shutdown, Unlock, ChangeTok,
+ ExUnlock, ExChangeTok };
+
+ /**
+ * Provide the talker with a list of selectable users. This can be used
+ * for autocompletion, etc.
+ * Will be called only when not running.
+ * @param users the users to load.
+ */
+ virtual void loadUsers( const QStringList &users ) = 0;
+
+ /**
+ * Preload the talker with an (opaque to the greeter) entity.
+ * Will be called only when not running.
+ * @param entity the entity to preload the talker with. That
+ * will usually be something like "user" or "user@domain".
+ * @param field the sub-widget (probably line edit) to put the cursor into.
+ * If -1, preselect the user for timed login. This means pre-filling
+ * the password field with anything, disabling it, and placing the
+ * cursor in the user name field.
+ */
+ virtual void presetEntity( const QString &entity, int field ) = 0;
+
+ /**
+ * Obtain the actually logged in entity.
+ * Will be called only after succeeded() was called.
+ */
+ virtual QString getEntity() const = 0;
+
+ /**
+ * "Push" a user into the talker. That can be a click into the user list
+ * or successful authentication without the talker calling gplugSetUser.
+ * Will be called only when running.
+ * @param user the user to set. Note that this is a UNIX login, not a
+ * canonical entity
+ */
+ virtual void setUser( const QString &user ) = 0;
+
+ /**
+ * En-/disable any widgets contained in the talker.
+ * Will be called only when not running.
+ * @param on the state to set
+ */
+ virtual void setEnabled( bool on ) = 0;
+
+ /**
+ * Called when a message from the authentication backend arrives.
+ * @param message the message received from the backend
+ * @param error if true, @p message is an error message, otherwise it's
+ * an informational message
+ * @return true means that the talker already handled the message, false
+ * that the greeter should display it in a message box
+ *
+ * FIXME: Filtering a message usually means that the backend issued a
+ * prompt and obtains the authentication data itself. However, in that
+ * state the backend is unresponsive, e.g., no shutdown is possible.
+ * The frontend could send the backend a signal, but the "escape path"
+ * within the backend is unclear (PAM won't like simply longjmp()ing
+ * out of it).
+ */
+ virtual bool textMessage( const char *message, bool error ) = 0;
+
+ /**
+ * Prompt the user for data. Reply by calling handler->gplugReturnText().
+ * @param propmt the prompt to display. It may be null, in which case
+ * "Username"/"Password" should be shown and the replies should be tagged
+ * with the respective Is* flag.
+ * @param echo if true, a normal input widget can be used, otherwise one that
+ * visually obscures the user's input.
+ * @param nonBlocking if true, report whatever is already available,
+ * otherwise wait for user input.
+ */
+ virtual void textPrompt( const char *prompt, bool echo, bool nonBlocking ) = 0;
+
+ /**
+ * Request binary authentication data from the talker. Reply by calling
+ * handler->gplugReturnBinary().
+ * @param prompt prompt in pam_client format
+ * @param nonBlocking if true, report whatever is already available,
+ * otherwise wait for user input.
+ * @return always true for now
+ *
+ * TODO:
+ * @return if true, the prompt was handled by the talker, otherwise the
+ * handler has to use libpam_client to obtain the authentication data.
+ * In that state the talker still can abort the data fetch by
+ * gplugReturn()ing a null array. When the data was obtained, another
+ * binaryPrompt with a null prompt will be issued.
+ */
+ virtual bool binaryPrompt( const char *prompt, bool nonBlocking ) = 0;
+
+ /**
+ * This can either
+ * - Start a processing cycle. Will be called only when not running.
+ * - Restart authTok cycle - will be called while running and implies
+ * revive(). PAM is a bit too clever, so we need this.
+ * In any case the talker is running afterwards.
+ */
+ virtual void start() = 0;
+
+ /**
+ * Request to suspend the auth. Make sure that a second talker of any
+ * type will be able to operate while this one is suspended (no busy
+ * device nodes, etc.).
+ * Will be called only if running within Login context. (Actually it
+ * won't be called at all, but be prepared.)
+ */
+ virtual void suspend() = 0;
+
+ /**
+ * Request to resume the auth from the point it was suspended at.
+ * Will be called only when suspended.
+ */
+ virtual void resume() = 0;
+
+ /**
+ * The "login" button was pressed in the greeter.
+ * This might call gplugReturn* or gplugStart.
+ * Will be called only when running.
+ */
+ virtual void next() = 0;
+
+ /**
+ * Abort auth cycle. Note that this should _not_ clear out already
+ * entered auth tokens if they are still on the screen.
+ * Will be called only when running and stops it.
+ */
+ virtual void abort() = 0;
+
+ /**
+ * Indicate successful end of the current phase.
+ * This is more or less a request to disable editable widgets
+ * responsible for the that phase.
+ * There will be no further attempt to enter that phase until the
+ * widget is destroyed.
+ * Will be called only when running and stops it.
+ */
+ virtual void succeeded() = 0;
+
+ /**
+ * Indicate unsuccessful end of the current phase.
+ * This is mostly a request to disable all editable widgets.
+ * The widget will be treated as dead until revive() is called.
+ * Will be called only when running and stops it.
+ */
+ virtual void failed() = 0;
+
+ /**
+ * Prepare retrying the previously failed phase.
+ * This is mostly a request to re-enable all editable widgets failed()
+ * disabled previously, clear the probably incorrect authentication tokens
+ * and to set the input focus appropriately.
+ * Will be called only after failed() (possibly with clear() in between),
+ * or after presetEntity() with field -1.
+ */
+ virtual void revive() = 0;
+
+ /**
+ * Clear any edit widgets, particularly anything set by setUser.
+ * Will be called only when not running.
+ */
+ virtual void clear() = 0;
+
+ typedef QList WidgetList;
+
+ /**
+ * Obtain the QWidget to actually handle the conversation.
+ */
+ const WidgetList &getWidgets() const { return widgetList; }
+
+protected:
+ KGreeterPluginHandler *handler;
+ WidgetList widgetList;
+};
+
+struct KDE_EXPORT KGreeterPluginInfo {
+ /**
+ * Human readable name of this plugin (should be a little more
+ * informative than just the libary name). Must be I18N_NOOP()ed.
+ */
+ const char *name;
+
+ /**
+ * The authentication method to use - the meaning is up to the backend,
+ * but will usually be related to the PAM service.
+ */
+ const char *method;
+
+ /**
+ * Capabilities.
+ */
+ enum {
+ /**
+ * All users exist on the local system permanently (will be listed
+ * by getpwent()); an entity corresponds to a UNIX user.
+ */
+ Local = 1,
+ /**
+ * The entities consist of multiple fields.
+ * PluginOptions/.FocusField is used instead of FocusPasswd.
+ */
+ Fielded = 2,
+ /**
+ * An entity can be preset, the talker has a widget where a user can
+ * be selected explicitly. If the method is "classic", timed login
+ * is possible, too.
+ * This also means that setUser/gplugSetUser can be used and a
+ * userlist can be shown at all - provided Local is set as well.
+ */
+ Presettable = 4
+ };
+
+ /*
+ * Capability flags.
+ */
+ int flags;
+
+ /**
+ * Call after loading the plugin.
+ *
+ * @param method if non-empty and the plugin is unable to handle that
+ * method, return false. If the plugin has a constant method defined
+ * above, it can ignore this parameter.
+ * @param getConf can be used to obtain configuration items from the
+ * greeter; you have to pass it the @p ctx pointer.
+ * The only predefined key (in KDM) is "EchoMode", which is an int
+ * (in fact, QLineEdit::EchoModes).
+ * Other keys are obtained from the PluginOptions option; see kdmrc
+ * for details.
+ * If the key is unknown, dflt is returned.
+ * @param ctx context pointer for @p getConf
+ * @return if false, unload the plugin again (don't call done() first)
+ */
+ bool (*init)( const QString &method,
+ QVariant (*getConf)( void *ctx, const char *key,
+ const QVariant &dflt ),
+ void *ctx );
+
+ /**
+ * Call before unloading the plugin.
+ * This pointer can be null.
+ */
+ void (*done)( void );
+
+ /**
+ * Factory method to create an instance of the plugin.
+ * Note that multiple instances can exist at one time, but only
+ * one of them is active at any moment (the others would be suspended
+ * or not running at all).
+ * @param handler the object offering the necessary callbacks
+ * @param parent parent widget
+ * @param predecessor the focus widget before the conversation widget
+ * @param fixedEntity see below
+ * @param func see below
+ * @param ctx see below
+ * @return an instance of this conversation plugin
+ *
+ * Valid combinations of Function and Context:
+ * - Authenticate:Login - init
+ * - Authenticate:Shutdown - init, for now "root" is passed as fixedEntitiy
+ * and it is not supposed to be displayed. Plugins with Local not set
+ * might have to conjure something up to make getEntity() return a
+ * canonical entitiy. FIXME: don't restrict shutdown to root.
+ * - AuthChAuthTok:Login, AuthChAuthTok:Shutdown - cont/cont,
+ * only relevant for classic method (as it is relevant only for password-
+ * less logins, which always use classic). The login should not be shown -
+ * it is known to the user already; the backend won't ask for it, either.
+ * - ChAuthTok:Login & ChAuthTok:Shutdown - cont
+ * - Authenticate:Unlock & Authenticate:ExUnlock - init,
+ * AuthChAuthTok:ChangeTok & AuthChAuthTok:ExChangeTok - init/cont,
+ * display fixedEntity as labels. The backend does not ask for the UNIX
+ * login, as it already knows it - but it will ask for all components of
+ * the entity if it is no UNIX login.
+ *
+ * "init" means that the plugin is supposed to call gplugStart, "cont"
+ * that the backend is already in a cycle of the method the plugin was
+ * initialized with (it does not hurt if gplugStart is still called).
+ */
+ KGreeterPlugin *(*create)( KGreeterPluginHandler *handler,
+ QWidget *parent,
+ const QString &fixedEntity,
+ KGreeterPlugin::Function func,
+ KGreeterPlugin::Context ctx );
+};
+
+#endif
diff --git a/ksysguard/CMakeLists.txt b/ksysguard/CMakeLists.txt
new file mode 100644
index 000000000..26298b550
--- /dev/null
+++ b/ksysguard/CMakeLists.txt
@@ -0,0 +1,13 @@
+
+########### next target ###############
+
+add_subdirectory( lsofui )
+add_subdirectory( processcore )
+add_subdirectory( processui )
+add_subdirectory( tests )
+
+check_include_files(sys/ptrace.h HAVE_SYS_PTRACE_H)
+
+configure_file(config-ksysguard.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-ksysguard.h )
+
+
diff --git a/ksysguard/config-ksysguard.h.cmake b/ksysguard/config-ksysguard.h.cmake
new file mode 100644
index 000000000..b495cb390
--- /dev/null
+++ b/ksysguard/config-ksysguard.h.cmake
@@ -0,0 +1,8 @@
+/* Define to 1 if you have the header file. */
+#cmakedefine HAVE_SYS_PTRACE_H 1
+
+/* Define to 1 if you have the header file. */
+#cmakedefine HAVE_SYS_ENDIAN_H 1
+
+/* Define to 1 if you have the header file. */
+#cmakedefine HAVE_BYTESWAP_H 1
diff --git a/ksysguard/lsofui/CMakeLists.txt b/ksysguard/lsofui/CMakeLists.txt
new file mode 100644
index 000000000..43c13478d
--- /dev/null
+++ b/ksysguard/lsofui/CMakeLists.txt
@@ -0,0 +1,33 @@
+
+########### next target ###############
+
+set(lsofui_LIB_SRCS
+ lsof.cpp
+)
+
+kde4_add_ui_files( lsofui_LIB_SRCS
+ LsofSearchWidget.ui
+)
+
+kde4_add_library(lsofui SHARED ${lsofui_LIB_SRCS})
+
+target_link_libraries(lsofui ${KDE4_KIO_LIBS} )
+set_target_properties(lsofui PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} )
+install(TARGETS lsofui ${INSTALL_TARGETS_DEFAULT_ARGS} )
+
+########### install files ###############
+
+install( FILES lsof.h DESTINATION ${INCLUDE_INSTALL_DIR}/ksysguard)
+
+set(ksysguardlsofwidgets_PART_SRCS
+ ${CMAKE_CURRENT_BINARY_DIR}/ksysguardlsofwidgets.cpp
+)
+
+KDE4_ADD_WIDGET_FILES(${ksysguardlsofwidgets_PART_SRCS} ksysguardlsof.widgets)
+
+kde4_add_plugin(ksysguardlsofwidgets ${ksysguardlsofwidgets_PART_SRCS})
+
+target_link_libraries(ksysguardlsofwidgets ${KDE4_KDECORE_LIBS} ${QT_QTGUI_LIBRARY} lsofui)
+
+install(TARGETS ksysguardlsofwidgets DESTINATION ${PLUGIN_INSTALL_DIR}/plugins/designer )
+
diff --git a/ksysguard/lsofui/LsofSearchWidget.cpp b/ksysguard/lsofui/LsofSearchWidget.cpp
new file mode 100644
index 000000000..45b45811d
--- /dev/null
+++ b/ksysguard/lsofui/LsofSearchWidget.cpp
@@ -0,0 +1,46 @@
+/*
+ KSysGuard, the KDE System Guard
+
+ Copyright (c) 1999 Chris Schlaeger
+ Copyright (c) 2007 John Tapsell
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+
+*/
+
+#include
+#include
+
+#include "LsofSearchWidget.moc"
+#include "ui_LsofSearchWidget.h"
+
+LsofSearchWidget::LsofSearchWidget(QWidget* parent, int pid )
+ : KDialog( parent )
+{
+ setObjectName( "Renice Dialog" );
+ setModal( true );
+ setCaption( i18n("Renice Process") );
+ setButtons( Close );
+ showButtonSeparator( false );
+ QWidget *widget = new QWidget(this);
+ setMainWidget(widget);
+ ui = new Ui_LsofSearchWidget();
+ ui->setupUi(widget);
+ ui->klsofwidget->setPid(pid);
+ ktreewidgetsearchline
+}
+
diff --git a/ksysguard/lsofui/LsofSearchWidget.h b/ksysguard/lsofui/LsofSearchWidget.h
new file mode 100644
index 000000000..ee0f89554
--- /dev/null
+++ b/ksysguard/lsofui/LsofSearchWidget.h
@@ -0,0 +1,45 @@
+/*
+ KSysGuard, the KDE System Guard
+
+ Copyright (c) 2008 John Tapsell
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef _LsofSearchWidget_h_
+#define _LsofSearchWidget_h_
+
+#include
+
+class Ui_LsofSearchWidget;
+
+/**
+ * This class creates and handles a simple dialog to change the scheduling
+ * priority of a process.
+ */
+class LsofSearchWidget : public KDialog
+{
+ Q_OBJECT
+
+public:
+ LsofSearchWidget(QWidget *parent);
+
+private:
+ Ui_LsofSearchWidget *ui;
+};
+
+#endif
diff --git a/ksysguard/lsofui/LsofSearchWidget.ui b/ksysguard/lsofui/LsofSearchWidget.ui
new file mode 100644
index 000000000..bb4f88a31
--- /dev/null
+++ b/ksysguard/lsofui/LsofSearchWidget.ui
@@ -0,0 +1,54 @@
+
+ KLsofSearchWidget
+
+
+
+ 0
+ 0
+ 956
+ 686
+
+
+
+ -
+
+
+ -
+
+
+ false
+
+
+
+ Stream
+
+
+
+
+ Type
+
+
+
+
+ Filename
+
+
+
+
+
+
+
+
+ KTreeWidgetSearchLine
+ KLineEdit
+
+
+
+ KLsofWidget
+ QTreeWidget
+
+
+
+
+
+
diff --git a/ksysguard/lsofui/Messages.sh b/ksysguard/lsofui/Messages.sh
new file mode 100755
index 000000000..915195e70
--- /dev/null
+++ b/ksysguard/lsofui/Messages.sh
@@ -0,0 +1,2 @@
+#! /usr/bin/env bash
+$XGETTEXT *.cpp -o $podir/ksysguardlsofwidgets.pot
diff --git a/ksysguard/lsofui/ksysguardlsof.widgets b/ksysguard/lsofui/ksysguardlsof.widgets
new file mode 100644
index 000000000..5673bee5b
--- /dev/null
+++ b/ksysguard/lsofui/ksysguardlsof.widgets
@@ -0,0 +1,8 @@
+[Global]
+PluginName=KSysGuardLsofWidgets
+
+[KLsofWidget]
+Group=KSysGuard (KDE)
+ConstructorArgs=(parent)
+IncludeFile=lsof.h
+
diff --git a/ksysguard/lsofui/lsof.cpp b/ksysguard/lsofui/lsof.cpp
new file mode 100644
index 000000000..755504f74
--- /dev/null
+++ b/ksysguard/lsofui/lsof.cpp
@@ -0,0 +1,86 @@
+#include
+#include
+#include
+
+#include "lsof.h"
+
+struct KLsofWidgetPrivate {
+ qlonglong pid;
+ QProcess *process;
+};
+
+KLsofWidget::KLsofWidget(QWidget *parent) : QTreeWidget(parent), d(new KLsofWidgetPrivate)
+{
+ d->pid = -1;
+ setColumnCount(3);
+ setUniformRowHeights(true);
+ setRootIsDecorated(false);
+ setItemsExpandable(false);
+ setSortingEnabled(true);
+ setAllColumnsShowFocus(true);
+ setHeaderLabels(QStringList() << i18nc("Short for File Descriptor", "FD") << i18n("Type") << i18n("Object"));
+ d->process = new QProcess(this);
+ connect(d->process, SIGNAL(finished ( int, QProcess::ExitStatus)), this, SLOT(finished(int, QProcess::ExitStatus)));
+}
+
+KLsofWidget::~KLsofWidget()
+{
+ delete d;
+}
+
+qlonglong KLsofWidget::pid() const
+{
+ return d->pid;
+}
+
+void KLsofWidget::setPid(qlonglong pid) {
+ d->pid = pid;
+ update();
+}
+
+bool KLsofWidget::update()
+{
+ clear();
+ QStringList args;
+ d->process->waitForFinished();
+ args << "-Fftn";
+ if(d->pid > 0)
+ args << ("-p" + QString::number(d->pid));
+ d->process->start("lsof", args);
+ return true;
+}
+
+void KLsofWidget::finished ( int exitCode, QProcess::ExitStatus exitStatus )
+{
+ char buf[1024];
+ QTreeWidgetItem *process = NULL;
+ while(true) {
+ qint64 lineLength = d->process->readLine(buf, sizeof(buf));
+
+ if(lineLength <= 0)
+ break;
+ if(buf[lineLength-1] == '\n')
+ lineLength--;
+
+ switch(buf[0]) {
+ /* Process related stuff */
+ case 'f':
+ process = new QTreeWidgetItem(this);
+ process->setText(0,QString::fromUtf8(buf+1, lineLength - 1));
+ break;
+ case 't':
+ if(process)
+ process->setText(1,QString::fromUtf8(buf+1, lineLength - 1));
+ break;
+
+ case 'n':
+ if(process)
+ process->setText(2,QString::fromUtf8(buf+1, lineLength - 1));
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+#include "lsof.moc"
diff --git a/ksysguard/lsofui/lsof.h b/ksysguard/lsofui/lsof.h
new file mode 100644
index 000000000..1b7bb3aaf
--- /dev/null
+++ b/ksysguard/lsofui/lsof.h
@@ -0,0 +1,83 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 2007 John Tapsell
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef LSOFWIDGET_H_
+#define LSOFWIDGET_H_
+
+#include
+#include
+#include
+#include
+
+struct KLsofWidgetPrivate;
+
+class KDE_EXPORT KLsofWidget : public QTreeWidget {
+ Q_OBJECT
+ Q_PROPERTY( qlonglong pid READ pid WRITE setPid )
+ public:
+ KLsofWidget(QWidget *parent = NULL);
+ ~KLsofWidget();
+ bool update();
+
+ private Q_SLOTS:
+ /* For QProcess *process */
+ //void error ( QProcess::ProcessError error );
+ void finished ( int exitCode, QProcess::ExitStatus exitStatus );
+ //void readyReadStandardError ();
+ //void readyReadStandardOutput ();
+ //void started ();
+ qlonglong pid() const;
+ void setPid(qlonglong pid);
+ private:
+ KLsofWidgetPrivate* const d;
+};
+
+/* class LsofProcessInfo {
+ public:
+ pid_t tpid;
+ int pidst;
+ pid_t pid;
+ pid_t ppid;
+ pid_t pgrp;
+ int uid;
+ QString cmd;
+ QString login;
+ };
+ class LsofFileInfo {
+ QString file_descriptor;
+ char access;
+ int file_struct_share_count;
+ char device_character_code;
+ long major_minor;
+ long file_struct_address;
+ long file_flags;
+ long inode;
+ long link_count;
+ char lock;
+ long file_struct_node_id;
+ long file_offset;
+ QString protocol_name;
+ QString stream_module;
+ QString file_type;
+ QString tcp_info;
+ };
+*/
+#endif
diff --git a/ksysguard/processcore/CMakeLists.txt b/ksysguard/processcore/CMakeLists.txt
new file mode 100644
index 000000000..d6946074c
--- /dev/null
+++ b/ksysguard/processcore/CMakeLists.txt
@@ -0,0 +1,28 @@
+
+########### next target ###############
+
+set(ksysguard_LIB_SRCS
+ processes.cpp
+ process.cpp
+ processes_local_p.cpp
+ processes_remote_p.cpp
+ processes_base_p.cpp
+)
+
+
+
+kde4_add_library(processcore SHARED ${ksysguard_LIB_SRCS})
+
+target_link_libraries(processcore ${KDE4_KDECORE_LIBS} )
+if( ${CMAKE_SYSTEM_NAME} MATCHES "NetBSD" )
+ message(STATUS "Adding kvm library on NetBSD")
+ target_link_libraries(processcore kvm)
+endif( ${CMAKE_SYSTEM_NAME} MATCHES "NetBSD" )
+
+set_target_properties(processcore PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} )
+install(TARGETS processcore ${INSTALL_TARGETS_DEFAULT_ARGS} )
+
+########### install files ###############
+
+install( FILES processes.h process.h DESTINATION ${INCLUDE_INSTALL_DIR}/ksysguard COMPONENT Devel)
+
diff --git a/ksysguard/processcore/Messages.sh b/ksysguard/processcore/Messages.sh
new file mode 100755
index 000000000..4cfeec253
--- /dev/null
+++ b/ksysguard/processcore/Messages.sh
@@ -0,0 +1,2 @@
+#! /usr/bin/env bash
+$XGETTEXT *.cpp -o $podir/processcore.pot
diff --git a/ksysguard/processcore/process.cpp b/ksysguard/processcore/process.cpp
new file mode 100644
index 000000000..673e0b24c
--- /dev/null
+++ b/ksysguard/processcore/process.cpp
@@ -0,0 +1,246 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 2007 John Tapsell
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "process.h"
+
+
+KSysGuard::Process::Process() {
+ clear();
+}
+KSysGuard::Process::Process(long long _pid, long long _ppid, Process *_parent) {
+ clear();
+ pid = _pid;
+ parent_pid = _ppid;
+ parent = _parent;
+}
+
+QString KSysGuard::Process::niceLevelAsString() const {
+ // Just some rough heuristic to map a number to how nice it is
+ if( niceLevel == 0) return i18nc("Process Niceness", "Normal");
+ if( niceLevel >= 10) return i18nc("Process Niceness", "Very low priority");
+ if( niceLevel > 0) return i18nc("Process Niceness", "Low priority");
+ if( niceLevel <= -10) return i18nc("Process Niceness", "Very high priority");
+ if( niceLevel < 0) return i18nc("Process Niceness", "High priority");
+ return QString(); //impossible;
+}
+
+QString KSysGuard::Process::ioniceLevelAsString() const {
+ // Just some rough heuristic to map a number to how nice it is
+ if( ioniceLevel == 4) return i18nc("Process Niceness", "Normal");
+ if( ioniceLevel >= 6) return i18nc("Process Niceness", "Very low priority");
+ if( ioniceLevel > 4) return i18nc("Process Niceness", "Low priority");
+ if( ioniceLevel <= 2) return i18nc("Process Niceness", "Very high priority");
+ if( ioniceLevel < 4) return i18nc("Process Niceness", "High priority");
+ return QString(); //impossible;
+
+}
+
+QString KSysGuard::Process::ioPriorityClassAsString() const {
+ switch( ioPriorityClass ) {
+ case None: return i18nc("Priority Class", "None");
+ case RealTime: return i18nc("Priority Class", "Real Time");
+ case BestEffort: return i18nc("Priority Class", "Best Effort");
+ case Idle: return i18nc("Priority Class", "Idle");
+ default: return i18nc("Priority Class", "Unknown");
+ }
+}
+
+QString KSysGuard::Process::translatedStatus() const {
+ switch( status ) {
+ case Running: return i18nc("process status", "running");
+ case Sleeping: return i18nc("process status", "sleeping");
+ case DiskSleep: return i18nc("process status", "disk sleep");
+ case Zombie: return i18nc("process status", "zombie");
+ case Stopped: return i18nc("process status", "stopped");
+ case Paging: return i18nc("process status", "paging");
+ default: return i18nc("process status", "unknown");
+ }
+}
+
+QString KSysGuard::Process::schedulerAsString() const {
+ switch( scheduler ) {
+ case Fifo: return i18nc("Scheduler", "FIFO");
+ case RoundRobin: return i18nc("Scheduler", "Round Robin");
+ case Batch: return i18nc("Scheduler", "Batch");
+ default: return QString();
+ }
+}
+
+void KSysGuard::Process::clear() {
+ pid = 0;
+ parent_pid = 0;
+ uid = 0;
+ gid = -1;
+ suid = euid = fsuid = -1;
+ sgid = egid = fsgid = -1;
+ tracerpid = 0;
+ userTime = -1;
+ sysTime = -1;
+ userUsage=0;
+ sysUsage=0;
+ totalUserUsage=0;
+ totalSysUsage=0;
+ numChildren=0;
+ niceLevel=0;
+ vmSize=0;
+ vmRSS = 0;
+ vmURSS = 0;
+ status=OtherStatus;
+ parent = NULL;
+ ioPriorityClass = None;
+ ioniceLevel = -1;
+ scheduler = Other;
+ changes = Process::Nothing;
+}
+void KSysGuard::Process::setLogin(QString _login) {
+ if(login == _login) return;
+ login = _login;
+ changes |= Process::Login;
+}
+void KSysGuard::Process::setUid(long long _uid) {
+ if(uid == _uid) return;
+ uid = _uid;
+ changes |= Process::Uids;
+}
+void KSysGuard::Process::setEuid(long long _euid) {
+ if(euid == _euid) return;
+ euid = _euid;
+ changes |= Process::Uids;
+}
+void KSysGuard::Process::setSuid(long long _suid) {
+ if(suid == _suid) return;
+ suid = _suid;
+ changes |= Process::Uids;
+}
+void KSysGuard::Process::setFsuid(long long _fsuid) {
+ if(fsuid == _fsuid) return;
+ fsuid = _fsuid;
+ changes |= Process::Uids;
+}
+
+void KSysGuard::Process::setGid(long long _gid) {
+ if(gid == _gid) return;
+ gid = _gid;
+ changes |= Process::Gids;
+}
+void KSysGuard::Process::setEgid(long long _egid) {
+ if(egid == _egid) return;
+ egid = _egid;
+ changes |= Process::Gids;
+}
+void KSysGuard::Process::setSgid(long long _sgid) {
+ if(sgid == _sgid) return;
+ sgid = _sgid;
+ changes |= Process::Gids;
+}
+void KSysGuard::Process::setFsgid(long long _fsgid) {
+ if(fsgid == _fsgid) return;
+ fsgid = _fsgid;
+ changes |= Process::Gids;
+}
+
+void KSysGuard::Process::setTracerpid(long long _tracerpid) {
+ if(tracerpid == _tracerpid) return;
+ tracerpid = _tracerpid;
+ changes |= Process::Tracerpid;
+}
+void KSysGuard::Process::setTty(QByteArray _tty) {
+ if(tty == _tty) return;
+ tty = _tty;
+ changes |= Process::Tty;
+}
+void KSysGuard::Process::setUserTime(long long _userTime) {
+ userTime = _userTime;
+}
+void KSysGuard::Process::setSysTime(long long _sysTime) {
+ sysTime = _sysTime;
+}
+void KSysGuard::Process::setUserUsage(int _userUsage) {
+ if(userUsage == _userUsage) return;
+ userUsage = _userUsage;
+ changes |= Process::Usage;
+}
+void KSysGuard::Process::setSysUsage(int _sysUsage) {
+ if(sysUsage == _sysUsage) return;
+ sysUsage = _sysUsage;
+ changes |= Process::Usage;
+}
+void KSysGuard::Process::setTotalUserUsage(int _totalUserUsage) {
+ if(totalUserUsage == _totalUserUsage) return;
+ totalUserUsage = _totalUserUsage;
+ changes |= Process::TotalUsage;
+}
+void KSysGuard::Process::setTotalSysUsage(int _totalSysUsage) {
+ if(totalSysUsage == _totalSysUsage) return;
+ totalSysUsage = _totalSysUsage;
+ changes |= Process::TotalUsage;
+}
+void KSysGuard::Process::setNiceLevel(int _niceLevel) {
+ if(niceLevel == _niceLevel) return;
+ niceLevel = _niceLevel;
+ changes |= Process::NiceLevels;
+}
+void KSysGuard::Process::setscheduler(Scheduler _scheduler) {
+ if(scheduler == _scheduler) return;
+ scheduler = _scheduler;
+ changes |= Process::NiceLevels;
+}
+void KSysGuard::Process::setIoPriorityClass(IoPriorityClass _ioPriorityClass) {
+ if(ioPriorityClass == _ioPriorityClass) return;
+ ioPriorityClass = _ioPriorityClass;
+ changes |= Process::NiceLevels;
+}
+void KSysGuard::Process::setIoniceLevel(int _ioniceLevel) {
+ if(ioniceLevel == _ioniceLevel) return;
+ ioniceLevel = _ioniceLevel;
+ changes |= Process::NiceLevels;
+}
+void KSysGuard::Process::setVmSize(long _vmSize) {
+ if(vmSize == _vmSize) return;
+ vmSize = _vmSize;
+ changes |= Process::VmSize;
+}
+void KSysGuard::Process::setVmRSS(long _vmRSS) {
+ if(vmRSS == _vmRSS) return;
+ vmRSS = _vmRSS;
+ changes |= Process::VmRSS;
+}
+void KSysGuard::Process::setVmURSS(long _vmURSS) {
+ if(vmURSS == _vmURSS) return;
+ vmURSS = _vmURSS;
+ changes |= Process::VmURSS;
+}
+void KSysGuard::Process::setName(QString _name) {
+ if(name == _name) return;
+ name = _name;
+ changes |= Process::Name;
+}
+void KSysGuard::Process::setCommand(QString _command) {
+ if(command == _command) return;
+ command = _command;
+ changes |= Process::Command;
+}
+void KSysGuard::Process::setStatus(ProcessStatus _status) {
+ if(status == _status) return;
+ status = _status;
+ changes |= Process::Status;
+}
+
diff --git a/ksysguard/processcore/process.h b/ksysguard/processcore/process.h
new file mode 100644
index 000000000..a1f4c6016
--- /dev/null
+++ b/ksysguard/processcore/process.h
@@ -0,0 +1,160 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 2007 John Tapsell
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef PROCESS_H_
+#define PROCESS_H_
+
+#include
+
+#include
+#include
+#include
+
+#include
+
+
+namespace KSysGuard
+{
+
+ class KDE_EXPORT Process {
+ public:
+ enum ProcessStatus { Running, Sleeping, DiskSleep, Zombie, Stopped, Paging, OtherStatus };
+ enum IoPriorityClass { None, RealTime, BestEffort, Idle };
+ enum Scheduler { Other = 0, Fifo, RoundRobin, Batch };
+ Process();
+ Process(long long _pid, long long _ppid, Process *_parent);
+
+ long pid; ///The system's ID for this process. 1 for init. 0 for our virtual 'parent of init' process used just for convience.
+ long parent_pid; ///The system's ID for the parent of this process. 0 for init.
+
+ /** A guaranteed NON-NULL pointer for all real processes to the parent process except for the fake process with pid 0.
+ * The Parent's pid is the same value as the parent_pid. The parent process will be also pointed
+ * to by ProcessModel::mPidToProcess to there is no need to worry about mem management in using parent.
+ * For init process, parent will point to a (fake) process with pid 0 to simplify things.
+ * For the fake process, this will point to NULL
+ */
+ Process *parent;
+
+ void setLogin(QString _login); ///The user login name. Only used for processes on remote machines. Otherwise use uid to get the name
+ void setUid(long long _uid); ///The user id that the process is running as
+ void setEuid(long long _euid); ///The effective user id that the process is running as
+ void setSuid(long long _suid); ///The set user id that the process is running as
+ void setFsuid(long long _fsuid); ///The file system user id that the process is running as.
+
+ void setGid(long long _gid); ///The process group id that the process is running as
+ void setEgid(long long _egid); ///The effective group id that the process is running as
+ void setSgid(long long _sgid); ///The set group id that the process is running as
+ void setFsgid(long long _fsgid); ///The file system group id that the process is running as
+
+ void setTracerpid(long long _tracerpid); ///If this is being debugged, this is the process that is debugging it
+ void setTty(QByteArray _tty); /// The name of the tty the process owns
+ void setUserTime(long long _userTime); ///The time, in 100ths of a second, spent in total on user calls. -1 if not known
+ void setSysTime(long long _sysTime); ///The time, in 100ths of a second, spent in total on system calls. -1 if not known
+ void setUserUsage(int _userUsage); ///Percentage (0 to 100). It might be more than 100% on multiple cpu core systems
+ void setSysUsage(int _sysUsage); ///Percentage (0 to 100). It might be more than 100% on multiple cpu core systems
+ void setTotalUserUsage(int _totalUserUsage); ///Percentage (0 to 100) from the sum of itself and all its children recursively. If there's no children, it's equal to userUsage. It might be more than 100% on multiple cpu core systems
+ void setTotalSysUsage(int _totalSysUsage); ///Percentage (0 to 100) from the sum of itself and all its children recursively. If there's no children, it's equal to sysUsage. It might be more than 100% on multiple cpu core systems
+ void setNiceLevel(int _niceLevel); ///If Scheduler = Other, niceLevel is the niceness (-20 to 20) of this process. A lower number means a higher priority. Otherwise sched priority (1 to 99)
+ void setscheduler(Scheduler _scheduler); ///The scheduler this process is running in. See man sched_getscheduler for more info
+ void setIoPriorityClass(IoPriorityClass _ioPriorityClass); /// The IO priority class. See man ionice for detailed information.
+ void setIoniceLevel(int _ioniceLevel); ///IO Niceness (0 to 7) of this process. A lower number means a higher io priority. -1 if not known or not applicable because ioPriorityClass is Idle or None
+ void setVmSize(long _vmSize); ///Virtual memory size in KiloBytes, including memory used, mmap'ed files, graphics memory etc,
+ void setVmRSS(long _vmRSS); ///Physical memory used by the process and its shared libraries. If the process and libraries are swapped to disk, this could be as low as 0
+ void setVmURSS(long _vmURSS); ///Physical memory used only by the process, and not counting the code for shared libraries. Set to -1 if unknown
+ void setName(QString _name); ///The name (e.g. "ksysguard", "konversation", "init")
+ void setCommand(QString _command); ///The command the process was launched with
+ void setStatus( ProcessStatus _status); ///Whether the process is running/sleeping/etc
+
+
+
+ QString login;
+ long long uid;
+ long long euid;
+ long long suid;
+ long long fsuid;
+
+ long long gid;
+ long long egid;
+ long long sgid;
+ long long fsgid;
+
+ long long tracerpid;
+ QByteArray tty;
+ long long userTime;
+ long long sysTime;
+ int userUsage;
+ int sysUsage;
+ int totalUserUsage;
+ int totalSysUsage;
+ unsigned long numChildren;
+ int niceLevel;
+ Scheduler scheduler;
+ IoPriorityClass ioPriorityClass;
+ int ioniceLevel;
+ long vmSize;
+ long vmRSS;
+ long vmURSS;
+ QString name;
+ QString command;
+ ProcessStatus status;
+
+ QList children; ///A list of all the direct children that the process has. Children of children are not listed here, so note that children_pids <= numChildren
+ QTime timeKillWasSent; /// This is usually a NULL time. When trying to kill a process, this is the time that the kill signal was sent to the process.
+
+ QString translatedStatus() const; /// Returns a translated string of the status. e.g. "Running" etc
+ QString niceLevelAsString() const; /// Returns a simple translated string of the nice priority. e.g. "Normal", "High", etc
+ QString ioniceLevelAsString() const; /// Returns a simple translated string of the io nice priority. e.g. "Normal", "High", etc
+ QString ioPriorityClassAsString() const; /// Returns a translated string of the io nice class. i.e. "None", "Real Time", "Best Effort", "Idle"
+ QString schedulerAsString() const; /// Returns a translated string of the scheduler class. e.g. "FIFO", "Round Robin", "Batch"
+
+ int index; /// Each process has a parent process. Each sibling has a unique number to identify it under that parent. This is that number.
+
+ /** An enum to keep track of what changed since the last update. Note that we
+ * the maximum we can use is 0x4000, so some of the enums represent multiple variables
+ */
+ enum Change {
+ Nothing = 0x0,
+ Uids = 0x1,
+ Gids = 0x2,
+ Tracerpid = 0x4,
+ Tty = 0x8,
+ Usage = 0x10,
+ TotalUsage = 0x20,
+ NiceLevels = 0x40,
+ VmSize = 0x80,
+ VmRSS = 0x100,
+ VmURSS = 0x200,
+ Name = 0x400,
+ Command = 0x800,
+ Status = 0x1000,
+ Login = 0x2000
+ };
+ Q_DECLARE_FLAGS(Changes, Change)
+
+ Changes changes; /** A QFlags representing what has changed */
+
+
+ private:
+ void clear();
+ };
+ Q_DECLARE_OPERATORS_FOR_FLAGS(Process::Changes)
+}
+
+#endif
diff --git a/ksysguard/processcore/processes.cpp b/ksysguard/processcore/processes.cpp
new file mode 100644
index 000000000..d62063837
--- /dev/null
+++ b/ksysguard/processcore/processes.cpp
@@ -0,0 +1,398 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 2007 John Tapsell
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "processes.h"
+#include "processes_base_p.h"
+#include "processes_local_p.h"
+#include "processes_remote_p.h"
+#include "process.h"
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+//for sysconf
+#include
+
+/* if porting to an OS without signal.h please #define SIGTERM to something */
+#include
+
+
+namespace KSysGuard
+{
+ Processes::StaticPrivate *Processes::d2 = 0;
+
+ class Processes::Private
+ {
+ public:
+ Private() { mAbstractProcesses = 0; mProcesses.insert(0, &mFakeProcess); mElapsedTimeCentiSeconds = -1; ref=1; }
+ ~Private();
+
+ QSet mToBeProcessed;
+ QSet mProcessedLastTime;
+
+ QHash mProcesses; //This must include mFakeProcess at pid 0
+ QList mListProcesses; //A list of the processes. Does not include mFakeProcesses
+ Process mFakeProcess; //A fake process with pid 0 just so that even init points to a parent
+
+ AbstractProcesses *mAbstractProcesses; //The OS specific code to get the process information
+ QTime mLastUpdated; //This is the time we last updated. Used to calculate cpu usage.
+ long mElapsedTimeCentiSeconds; //The number of centiseconds (100ths of a second) that passed since the last update
+
+ int ref; //Reference counter. When it reaches 0, delete.
+ };
+
+ class Processes::StaticPrivate
+ {
+ public:
+ StaticPrivate() { processesLocal = 0; ref =1; }
+ Processes *processesLocal;
+ QHash processesRemote;
+ int ref; //Reference counter. When it reaches 0, delete.
+ };
+
+Processes::Private::~Private() {
+ foreach(Process *process, mProcesses) {
+ if(process != &mFakeProcess)
+ delete process;
+ }
+ mProcesses.clear();
+ mListProcesses.clear();
+ delete mAbstractProcesses;
+ mAbstractProcesses = NULL;
+}
+
+Processes *Processes::getInstance(const QString &host) { //static
+ if(!d2) {
+ d2 = new StaticPrivate();
+ } else {
+ d2->ref++;
+ }
+ if(host.isEmpty()) {
+ //Localhost processes
+ if(!d2->processesLocal) {
+ KGlobal::locale()->insertCatalog("processcore"); //Make sure we include the translation stuff. This needs to be run before any i18n call here
+ d2->processesLocal = new Processes(new ProcessesLocal());
+ } else {
+ d2->processesLocal->d->ref++;
+ }
+ return d2->processesLocal;
+ } else {
+ Processes *processes = d2->processesRemote.value(host, NULL);
+ if( !processes ) {
+ //connect to it
+ KGlobal::locale()->insertCatalog("processcore"); //Make sure we include the translation stuff. This needs to be run before any i18n call here
+ ProcessesRemote *remote = new ProcessesRemote(host);
+ processes = new Processes( remote );
+ d2->processesRemote.insert(host, processes);
+ connect(remote, SIGNAL(runCommand(const QString &, int )), processes, SIGNAL(runCommand(const QString&, int)));
+ } else {
+ processes->d->ref++;
+ }
+ return processes;
+ }
+}
+
+void Processes::returnInstance(const QString &host) { //static
+ if(!d2) {
+ kDebug() << "Internal error - static class does not exist";
+ return;
+ }
+ if(host.isEmpty()) {
+ //Localhost processes
+ if(!d2->processesLocal) {
+ //Serious error. Returning instance we don't have.
+ kDebug() << "Internal error - returning instance we do not have";
+ return;
+ } else {
+ if(--(d2->processesLocal->d->ref) == 0) {
+ delete d2->processesLocal;
+ d2->processesLocal = NULL;
+ }
+ }
+ } else {
+ Processes *processes = d2->processesRemote.value(host, NULL);
+ if( !processes ) {
+ kDebug() << "Internal error - returning instance we do not have";
+ return;
+ } else {
+ if(--(processes->d->ref) == 0) {
+ delete processes;
+ d2->processesRemote.remove(host);
+ }
+ }
+ }
+ if(--(d2->ref) == 0) {
+ delete d2;
+ d2 = NULL;
+ }
+
+}
+Processes::Processes(AbstractProcesses *abstractProcesses) : d(new Private())
+{
+ d->mAbstractProcesses = abstractProcesses;
+ connect( abstractProcesses, SIGNAL( processesUpdated() ), SLOT( processesUpdated() ));
+}
+
+Processes::~Processes()
+{
+ delete d;
+}
+Process *Processes::getProcess(long pid) const
+{
+ return d->mProcesses.value(pid);
+}
+
+QList Processes::getAllProcesses() const
+{
+ return d->mListProcesses;
+}
+bool Processes::updateProcess( Process *ps, long ppid, bool onlyReparent)
+{
+ Process *parent = d->mProcesses.value(ppid);
+ Q_ASSERT(parent); //even init has a non-null parent - the mFakeProcess
+
+ if(ps->parent != parent) {
+ emit beginMoveProcess(ps, parent/*new parent*/);
+ //Processes has been reparented
+ Process *p = ps;
+ do {
+ p = p->parent;
+ p->numChildren--;
+ } while (p->pid!= 0);
+ ps->parent->children.removeAll(ps);
+ ps->parent = parent; //the parent has changed
+ parent->children.append(ps);
+ p = ps;
+ do {
+ p = p->parent;
+ p->numChildren++;
+ } while (p->pid!= 0);
+ emit endMoveProcess();
+ }
+ if(onlyReparent)
+ return true;
+
+ ps->parent = parent;
+ ps->parent_pid = ppid;
+
+ //Now we can actually get the process info
+ long oldUserTime = ps->userTime;
+ long oldSysTime = ps->sysTime;
+ ps->changes = Process::Nothing;
+ bool success = d->mAbstractProcesses->updateProcessInfo(ps->pid, ps);
+
+ //Now we have the process info. Calculate the cpu usage and total cpu usage for itself and all its parents
+ if(oldUserTime != -1 && d->mElapsedTimeCentiSeconds!= 0) { //Update the user usage and sys usage
+#ifndef Q_OS_NETBSD
+ ps->setUserUsage((int)(((ps->userTime - oldUserTime)*100.0 + 0.5) / d->mElapsedTimeCentiSeconds));
+ ps->setSysUsage((int)(((ps->sysTime - oldSysTime)*100.0 + 0.5) / d->mElapsedTimeCentiSeconds));
+#endif
+ ps->setTotalUserUsage(ps->userUsage);
+ ps->setTotalSysUsage(ps->sysUsage);
+ if(ps->userUsage != 0 || ps->sysUsage != 0) {
+ Process *p = ps->parent;
+ while(p->pid != 0) {
+ p->totalUserUsage += ps->userUsage;
+ p->totalSysUsage += ps->sysUsage;
+ emit processChanged(p, true);
+ p= p->parent;
+ }
+ }
+ }
+
+ emit processChanged(ps, false);
+
+ return success;
+
+}
+bool Processes::addProcess(long pid, long ppid)
+{
+ Process *parent = d->mProcesses.value(ppid);
+ if(!parent) return false; //How can this be?
+ //it's a new process - we need to set it up
+ Process *ps = new Process(pid, ppid, parent);
+
+ emit beginAddProcess(ps);
+
+ d->mProcesses.insert(pid, ps);
+
+ ps->index = d->mListProcesses.count();
+ d->mListProcesses.append(ps);
+
+ ps->parent->children.append(ps);
+ Process *p = ps;
+ do {
+ p = p->parent;
+ p->numChildren++;
+ } while (p->pid!= 0);
+ ps->parent_pid = ppid;
+
+ //Now we can actually get the process info
+ bool success = d->mAbstractProcesses->updateProcessInfo(pid, ps);
+ emit endAddProcess();
+ return success;
+
+}
+bool Processes::updateOrAddProcess( long pid)
+{
+ long ppid = d->mAbstractProcesses->getParentPid(pid);
+
+ if(d->mToBeProcessed.contains(ppid)) {
+ //Make sure that we update the parent before we update this one. Just makes things a bit easier.
+ d->mToBeProcessed.remove(ppid);
+ d->mProcessedLastTime.remove(ppid); //It may or may not be here - remove it if it is there
+ updateOrAddProcess(ppid);
+ }
+
+ Process *ps = d->mProcesses.value(pid, 0);
+ if(!ps)
+ return addProcess(pid, ppid);
+ else
+ return updateProcess(ps, ppid);
+}
+
+void Processes::updateAllProcesses( long updateDurationMS )
+{
+ if(d->mElapsedTimeCentiSeconds == -1) {
+ //First time update has been called
+ d->mLastUpdated.start();
+ d->mElapsedTimeCentiSeconds = 0;
+ } else {
+ if(d->mLastUpdated.elapsed() < updateDurationMS) //don't update more often than the time given
+ return;
+ d->mElapsedTimeCentiSeconds = d->mLastUpdated.restart() / 10;
+ }
+
+ d->mAbstractProcesses->updateAllProcesses();
+}
+
+void Processes::processesUpdated() {
+ d->mToBeProcessed = d->mAbstractProcesses->getAllPids();
+
+ QSet beingProcessed(d->mToBeProcessed); //keep a copy so that we can replace mProcessedLastTime with this at the end of this function
+
+ long pid;
+ {
+ QMutableSetIterator i(d->mToBeProcessed);
+ while( i.hasNext()) {
+ pid = i.next();
+ i.remove();
+ d->mProcessedLastTime.remove(pid); //It may or may not be here - remove it if it is there
+ updateOrAddProcess(pid); //This adds the process or changes an extisting one
+ i.toFront(); //we can remove entries from this set elsewhere, so our iterator might be invalid. reset it back to the start of the set
+ }
+ }
+ {
+ QMutableSetIterator i(d->mProcessedLastTime);
+ while( i.hasNext()) {
+ //We saw these pids last time, but not this time. That means we have to delete them now
+ pid = i.next();
+ i.remove();
+ deleteProcess(pid);
+ i.toFront();
+ }
+ }
+
+ d->mProcessedLastTime = beingProcessed; //update the set for next time this function is called
+ return;
+}
+
+
+void Processes::deleteProcess(long pid)
+{
+ Q_ASSERT(pid > 0);
+
+ Process *process = d->mProcesses.value(pid);
+ foreach( Process *it, process->children) {
+ d->mProcessedLastTime.remove(it->pid);
+ deleteProcess(it->pid);
+ }
+
+ emit beginRemoveProcess(process);
+
+ d->mProcesses.remove(pid);
+ d->mListProcesses.removeAll(process);
+ process->parent->children.removeAll(process);
+ Process *p = process;
+ do {
+ p = p->parent;
+ p->numChildren--;
+ } while (p->pid!= 0);
+
+ int i=0;
+ foreach( Process *it, d->mListProcesses ) {
+ if(it->index > process->index)
+ it->index--;
+ Q_ASSERT(it->index == i++);
+ }
+
+ delete process;
+ emit endRemoveProcess();
+}
+
+
+bool Processes::killProcess(long pid) {
+ return sendSignal(pid, SIGTERM);
+}
+
+bool Processes::sendSignal(long pid, int sig) {
+ return d->mAbstractProcesses->sendSignal(pid, sig);
+}
+
+bool Processes::setNiceness(long pid, int priority) {
+ return d->mAbstractProcesses->setNiceness(pid, priority);
+}
+
+bool Processes::setScheduler(long pid, KSysGuard::Process::Scheduler priorityClass, int priority) {
+ return d->mAbstractProcesses->setScheduler(pid, priorityClass, priority);
+}
+
+bool Processes::setIoNiceness(long pid, KSysGuard::Process::IoPriorityClass priorityClass, int priority) {
+ return d->mAbstractProcesses->setIoNiceness(pid, priorityClass, priority);
+}
+
+bool Processes::supportsIoNiceness() {
+ return d->mAbstractProcesses->supportsIoNiceness();
+}
+
+long long Processes::totalPhysicalMemory() {
+ return d->mAbstractProcesses->totalPhysicalMemory();
+}
+
+long Processes::numberProcessorCores() {
+ return d->mAbstractProcesses->numberProcessorCores();
+}
+
+void Processes::answerReceived( int id, const QList& answer ) {
+ KSysGuard::ProcessesRemote *processes = dynamic_cast(d->mAbstractProcesses);
+ if(processes)
+ processes->answerReceived(id, answer);
+}
+
+}
+#include "processes.moc"
+
diff --git a/ksysguard/processcore/processes.h b/ksysguard/processcore/processes.h
new file mode 100644
index 000000000..c5f80ad51
--- /dev/null
+++ b/ksysguard/processcore/processes.h
@@ -0,0 +1,224 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 2007 John Tapsell
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef PROCESSES_H_
+#define PROCESSES_H_
+
+#include
+
+#include "process.h"
+#include
+
+namespace KSysGuard
+{
+ class AbstractProcesses;
+ /**
+ * This class retrieves the processes currently running in an OS independent way.
+ *
+ * To use, do something like:
+ *
+ * \code
+ * #include
+ * #include
+ *
+ * KSysGuard::Processes *processes = KSysGuard::Processes::getInstance();
+ * QHash processlist = processes->getProcesses();
+ * foreach( Process * process, processlist) {
+ * kDebug() << "Process with pid " << process->pid << " is called " << process->name;
+ * }
+ * KSysGuard::Processes::returnInstance(processes);
+ * processes = NULL;
+ * \endcode
+ *
+ * @author John Tapsell
+ */
+ class KDE_EXPORT Processes : public QObject
+ {
+ Q_OBJECT
+
+ public:
+ /**
+ * Singleton pattern to return the instance associated with @p host.
+ * Leave as the default for the current machine
+ */
+ static Processes *getInstance(const QString &host = QString());
+ /**
+ * Call when you are finished with the Processes pointer from getInstance.
+ * The pointer from getInstance may not be valid after calling this.
+ * This is reference counted - once all the instances are returned, the object is deleted
+ */
+ static void returnInstance(const QString &host = QString());
+
+ /**
+ * Update all the process information. After calling this, /proc or equivalent is scanned and
+ * the signals processChanged, etc are emitted.
+ *
+ * Set updateDuration to whatever time period that you update, in milliseconds.
+ * For example, if you update every 2000ms, set this to 2000. That way it won't update
+ * more often than needed
+ */
+ void updateAllProcesses(long updateDurationMS = 0);
+ /**
+ * Return information for one specific process. call getProcess(0) to get the
+ * fake process used as the top most parent for all processes.
+ * This doesn't fetch any new information and so returns almost instantly.
+ * Call updateAllProcesses() to actually fetch the process information.
+ */
+ Process *getProcess(long pid) const;
+
+ /**
+ * Kill the specified process. You may not have the privillage to kill the process.
+ * The process may also chose to ignore the command. Send the SIGKILL signal to kill
+ * the process immediately. You may lose any unsaved data.
+ *
+ * @returns Successful or not in killing the process
+ */
+ bool killProcess(long pid);
+
+ /**
+ * Send the specified named POSIX signal to the process given.
+ *
+ * For example, to indicate for process 324 to STOP do:
+ * \code
+ * #include
+ * ...
+ *
+ * KSysGuard::Processes::sendSignal(23, SIGSTOP);
+ * \endcode
+ *
+ */
+ bool sendSignal(long pid, int sig);
+
+ /**
+ * Set the priority for a process. This is from 19 (very nice, lowest priority) to
+ * -20 (highest priority). The default value for a process is 0.
+ *
+ * @return false if you do not have permission to set the priority
+ */
+ bool setNiceness(long pid, int priority);
+
+ /**
+ * Set the scheduler for a process. This is defined according to POSIX.1-2001
+ * See "man sched_setscheduler" for more information.
+ *
+ * @p priorityClass One of SCHED_FIFO, SCHED_RR, SCHED_OTHER, and SCHED_BATCH
+ * @p priority Set to 0 for SCHED_OTHER and SCHED_BATCH. Between 1 and 99 for SCHED_FIFO and SCHED_RR
+ * @return false if you do not have permission to set the priority
+ */
+ bool setScheduler(long pid, KSysGuard::Process::Scheduler priorityClass, int priority);
+
+ /**
+ * Set the io priority for a process. This is from 7 (very nice, lowest io priority) to
+ * 0 (highest priority). The default value is determined as: io_nice = (cpu_nice + 20) / 5.
+ *
+ * @return false if you do not have permission to set the priority
+ */
+ bool setIoNiceness(long pid, KSysGuard::Process::IoPriorityClass priorityClass, int priority);
+
+ /**
+ * Returns true if ionice is supported on this system
+ */
+ bool supportsIoNiceness();
+
+ /**
+ * Return the internal pointer of all the processes. The order of the processes
+ * is guaranteed to never change. Call updateAllProcesses first to actually
+ * update the information.
+ */
+ QList< Process *> getAllProcesses() const;
+
+ /**
+ * Return the total amount of physical memory in KB. This is fast (just a system call)
+ * Returns 0 on error
+ */
+ long long totalPhysicalMemory();
+
+ /**
+ * Return the number of processor cores enabled.
+ * (A system can disable procesors. Disabled processors are not counted here).
+ * This is fast (just a system call) */
+ long numberProcessorCores();
+
+ public Q_SLOTS:
+ /** The abstract processes has updated its list of processes */
+ void processesUpdated();
+
+ Q_SIGNALS:
+ /** The data for a process has changed.
+ * if @p onlyTotalCpu is set, only the total cpu usage has been updated.
+ * process->changes contains a bit field indicating what has changed since the last time this was emitted
+ * for this process
+ */
+ void processChanged( KSysGuard::Process *process, bool onlyTotalCpu);
+ /**
+ * This indicates we are about to add a process in the model.
+ * The process already has the pid, ppid and tree_parent set up.
+ */
+ void beginAddProcess( KSysGuard::Process *process);
+ /**
+ * We have finished inserting a process
+ */
+ void endAddProcess();
+ /**
+ * This indicates we are about to remove a process in the model. Emit the appropriate signals
+ */
+ void beginRemoveProcess( KSysGuard::Process *process);
+ /**
+ * We have finished removing a process
+ */
+ void endRemoveProcess();
+ /**
+ * This indicates we are about move a process from one parent to another.
+ */
+ void beginMoveProcess(KSysGuard::Process *process, KSysGuard::Process *new_parent);
+ /**
+ * We have finished moving the process
+ */
+ void endMoveProcess();
+ protected:
+ Processes(AbstractProcesses *abstractProcesses);
+ ~Processes();
+ class Private;
+ Private *d;
+ class StaticPrivate;
+ static StaticPrivate *d2;
+ private:
+ bool updateOrAddProcess( long pid);
+ inline void deleteProcess(long pid);
+ bool updateProcess( Process *process, long ppid, bool onlyReparent = false);
+ bool addProcess(long pid, long ppid);
+
+
+ Q_SIGNALS:
+ /** For a remote machine, we rely on being able to communicate with ksysguardd.
+ * This must be dealt with by the program including this widget. It must listen to our
+ * 'runCommand' signal, and run the given command, with the given id. */
+ void runCommand(const QString &command, int id);
+
+ public:
+ /** For a remote machine, we rely on being able to communicate with ksysguardd.
+ * The programming using this must call this slot when an answer is received from ksysguardd,
+ * in response to a runCommand request. The id identifies the answer */
+ void answerReceived( int id, const QList& answer );
+
+ };
+}
+#endif
diff --git a/ksysguard/processcore/processes_base_p.cpp b/ksysguard/processcore/processes_base_p.cpp
new file mode 100644
index 000000000..ea8be5623
--- /dev/null
+++ b/ksysguard/processcore/processes_base_p.cpp
@@ -0,0 +1,22 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 2007 John Tapsell
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "processes_base_p.moc"
diff --git a/ksysguard/processcore/processes_base_p.h b/ksysguard/processcore/processes_base_p.h
new file mode 100644
index 000000000..5acd9568b
--- /dev/null
+++ b/ksysguard/processcore/processes_base_p.h
@@ -0,0 +1,139 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 2007 John Tapsell
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef PROCESSES_BASE_P_H
+#define PROCESSES_BASE_P_H
+
+#include
+#include
+
+namespace KSysGuard
+{
+ class Process;
+ /**
+ * This class contains the specific code to get the processes from the given host.
+ *
+ * To port this to other operating systems you need to make a processes_(osname).cpp file
+ * which implements all of the function below. If you need private functions/variables etc put them in
+ * the Private class.
+ *
+ * @author John Tapsell
+ */
+ class AbstractProcesses : public QObject
+ {
+ Q_OBJECT
+
+ public:
+
+ AbstractProcesses() {}
+ virtual ~AbstractProcesses() {}
+ /**
+ * To get information about processes, this will be the first function called.
+ */
+ virtual QSet getAllPids() = 0;
+ /**
+ * For each of the pids that getAllPids() returns, getParentPid will be called. This is used to setup the tree structure.
+ * For a particular pid, this is guaranteed to be called before updateProcessInfo for that pid.
+ * However this may be called several times in a row before the updateProcessInfo is called, so be careful
+ * if you want to try to preserve state in Private.
+ */
+ virtual long getParentPid(long pid) = 0;
+ /**
+ * This will be called for every pid, after getParentPid() has been called for the same parameter.
+ *
+ * The process->pid process->ppid and process->parent are all guaranteed to be filled in correctly and process->parent
+ * will be non null.
+ */
+ virtual bool updateProcessInfo(long pid, Process *process) = 0;
+ /**
+ * Send the specified named POSIX signal to the process given.
+ *
+ * For example, to indicate for process 324 to STOP do:
+ * \code
+ * #include
+ * ...
+ *
+ * KSysGuard::Processes::sendSignal(23, SIGSTOP);
+ * \endcode
+ *
+ */
+ virtual bool sendSignal(long pid, int sig) = 0;
+
+ /**
+ * Set the priority for a process. For the normal scheduler, this is usually from 19
+ * (very nice, lowest priority) to -20 (highest priority). The default value for a process is 0.
+ *
+ * This has no effect if the scheduler is not the normal one (SCHED_OTHER)
+ *
+ * @return false if you do not have permission to set the priority
+ */
+ virtual bool setNiceness(long pid, int priority) = 0;
+
+ /**
+ * Set the scheduler for a process. This is defined according to POSIX.1-2001
+ * See "man sched_setscheduler" for more information.
+ *
+ * @p priorityClass One of SCHED_FIFO, SCHED_RR, SCHED_OTHER, and SCHED_BATCH
+ * @p priority Set to 0 for SCHED_OTHER and SCHED_BATCH. Between 1 and 99 for SCHED_FIFO and SCHED_RR
+ * @return false if you do not have permission to set the priority
+ */
+ virtual bool setScheduler(long pid, int priorityClass, int priority) = 0;
+
+ /**
+ * Return the total amount of physical memory in KB. This is fast (just a system call)
+ * Returns 0 on error
+ */
+ virtual long long totalPhysicalMemory() = 0;
+
+ /**
+ * Set the io priority for a process. This is from 7 (very nice, lowest io priority) to
+ * 0 (highest priority). The default value is determined as: io_nice = (cpu_nice + 20) / 5.
+ *
+ * @return false if you do not have permission to set the priority
+ */
+ virtual bool setIoNiceness(long pid, int priorityClass, int priority) = 0;
+
+ /**
+ * Returns true if ionice is supported on this system
+ */
+ virtual bool supportsIoNiceness() = 0;
+
+ /**
+ * Return the number of processor cores enabled.
+ * (A system can disable procesors. Disabled processors are not counted here).
+ * This is fast (just a system call) */
+ virtual long numberProcessorCores() = 0;
+
+ /**
+ * Get all the current process information from the machine. When done, emit updateAllProcesses().
+ */
+ virtual void updateAllProcesses() = 0;
+
+ Q_SIGNALS:
+ /**
+ * This is emitted when the processes have been updated, and the view should be refreshed
+ */
+ void processesUpdated();
+
+ };
+}
+
+#endif // PROCESSES_BASE_P_H
diff --git a/ksysguard/processcore/processes_freebsd_p.cpp b/ksysguard/processcore/processes_freebsd_p.cpp
new file mode 100644
index 000000000..b5fc34986
--- /dev/null
+++ b/ksysguard/processcore/processes_freebsd_p.cpp
@@ -0,0 +1,307 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Manolo Valdes
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "processes_local_p.h"
+#include "process.h"
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#if defined(__DragonFly__)
+#include
+#include
+#endif
+#include
+#include
+#include
+#include
+
+
+
+namespace KSysGuard
+{
+
+ class ProcessesLocal::Private
+ {
+ public:
+ Private() {;}
+ ~Private() {;}
+ inline bool readProc(long pid, struct kinfo_proc *p);
+ inline void readProcStatus(struct kinfo_proc *p, Process *process);
+ inline void readProcStat(struct kinfo_proc *p, Process *process);
+ inline void readProcStatm(struct kinfo_proc *p, Process *process);
+ inline bool readProcCmdline(long pid, Process *process);
+ };
+
+bool ProcessesLocal::Private::readProc(long pid, struct kinfo_proc *p)
+{
+ int mib[4];
+ size_t len;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = pid;
+
+ len = sizeof (struct kinfo_proc);
+ if (sysctl(mib, 4, p, &len, NULL, 0) == -1 || !len)
+ return false;
+ return true;
+}
+
+void ProcessesLocal::Private::readProcStatus(struct kinfo_proc *p, Process *process)
+{
+ process->setUid(0);
+ process->setGid(0);
+ process->setTracerpid(0);
+
+
+#if defined(__FreeBSD__) && __FreeBSD_version >= 500015
+ process->setUid(p->ki_uid);
+ process->setGid(p->ki_pgid);
+ process->setName(QString(p->ki_comm ? p->ki_comm : "????"));
+#elif defined(__DragonFly__) && __DragonFly_version >= 190000
+ process->setUid(p->kp_uid);
+ process->setGid(p->kp_pgid);
+ process->setName(QString(p->kp_comm ? p->kp_comm : "????"));
+#else
+ process->setUid(p->kp_eproc.e_ucred.cr_uid);
+ process->setGid(p->kp_eproc.e_pgid);
+#endif
+}
+
+void ProcessesLocal::Private::readProcStat(struct kinfo_proc *p, Process *ps)
+{
+ int status;
+ struct rusage pru;
+#if defined(__FreeBSD__) && __FreeBSD_version >= 500015
+ ps->setUserTime(p->ki_runtime / 10000);
+ ps->setNiceLevel(p->ki_nice);
+ ps->setVmSize(p->ki_size);
+ ps->setVmRSS(p->ki_rssize * getpagesize());
+ status = p->ki_stat;
+#elif defined(__DragonFly__) && __DragonFly_version >= 190000
+ if (!getrusage(p->kp_pid, &pru)) {
+ errx(1, "failed to get rusage info");
+ }
+ ps->setUserTime(pru.ru_utime.tv_usec / 1000); /*p_runtime / 1000*/
+ ps->setNiceLevel(p->kp_nice);
+ ps->setVmSize(p->kp_vm_map_size);
+ ps->setVmRSS(p->kp_vm_rssize * getpagesize());
+ status = p->kp_stat;
+#else
+ ps->setUserTime(p->kp_proc.p_rtime.tv_sec*100+p->kp_proc.p_rtime.tv_usec/100);
+ ps->setNiceLevel(p->kp_proc.p_nice);
+ ps->setVmSize(p->kp_eproc.e_vm.vm_map.size);
+ ps->setVmRSS(p->kp_eproc.e_vm.vm_rssize * getpagesize());
+ status = p->kp_proc.p_stat;
+#endif
+ ps->setSysTime(0);
+
+// "idle","run","sleep","stop","zombie"
+ switch( status ) {
+ case '0':
+ ps->setStatus(Process::DiskSleep);
+ break;
+ case '1':
+ ps->setStatus(Process::Running);
+ break;
+ case '2':
+ ps->setStatus(Process::Sleeping);
+ break;
+ case '3':
+ ps->setStatus(Process::Stopped);
+ break;
+ case '4':
+ ps->setStatus(Process::Zombie);
+ break;
+ default:
+ ps->setStatus(Process::OtherStatus);
+ break;
+ }
+}
+
+void ProcessesLocal::Private::readProcStatm(struct kinfo_proc *p, Process *process)
+{
+// TODO
+
+// unsigned long shared;
+// process->setVmURSS(process->vmRSS - (shared * sysconf(_SC_PAGESIZE) / 1024));
+}
+
+bool ProcessesLocal::Private::readProcCmdline(long pid, Process *process)
+{
+ int mib[4];
+ struct kinfo_proc p;
+ size_t buflen = 256;
+ char buf[256];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_ARGS;
+ mib[3] = pid;
+
+ if (sysctl(mib, 4, buf, &buflen, NULL, 0) == -1 || !buflen)
+ return false;
+ QString command = QString(buf);
+
+ //cmdline seperates parameters with the NULL character
+ command = command.replace('\0', ' ');
+ process->setCommand(command.trimmed());
+
+ return true;
+}
+
+ProcessesLocal::ProcessesLocal() : d(new Private())
+{
+
+}
+
+long ProcessesLocal::getParentPid(long pid) {
+ long long ppid = 0;
+ struct kinfo_proc p;
+ if(d->readProc(pid, &p))
+ {
+#if defined(__FreeBSD__) && __FreeBSD_version >= 500015
+ ppid = p.ki_ppid;
+#elif defined(__DragonFly__) && __DragonFly_version >= 190000
+ ppid = p.kp_ppid;
+#else
+ ppid = p.kp_eproc.e_ppid;
+#endif
+ }
+ return ppid;
+}
+
+bool ProcessesLocal::updateProcessInfo( long pid, Process *process)
+{
+ struct kinfo_proc p;
+ if(!d->readProc(pid, &p)) return false;
+ d->readProcStat(&p, process);
+ d->readProcStatus(&p, process);
+ d->readProcStatm(&p, process);
+ if(!d->readProcCmdline(pid, process)) return false;
+
+ return true;
+}
+
+QSet ProcessesLocal::getAllPids( )
+{
+ QSet pids;
+ int mib[3];
+ size_t len;
+ size_t num;
+ struct kinfo_proc *p;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_ALL;
+ sysctl(mib, 3, NULL, &len, NULL, 0);
+ p = (kinfo_proc *) malloc(len);
+ sysctl(mib, 3, p, &len, NULL, 0);
+
+ for (num = 0; num < len / sizeof(struct kinfo_proc); num++)
+ {
+#if defined(__FreeBSD__) && __FreeBSD_version >= 500015
+ long pid = p[num].ki_pid;
+ long long ppid = p[num].ki_ppid;
+#elif defined(__DragonFly__) && __DragonFly_version >= 190000
+ long pid = p[num].kp_pid;
+ long long ppid = p[num].kp_ppid;
+#else
+ long pid = p[num].kp_proc.p_pid;
+ long long ppid = p[num].kp_eproc.e_ppid;
+#endif
+ //skip all process with parent id = 0 but init
+ if(ppid == 0 && pid != 1)
+ continue;
+ pids.insert(pid);
+ }
+ free(p);
+ return pids;
+}
+
+bool ProcessesLocal::sendSignal(long pid, int sig) {
+ if ( kill( (pid_t)pid, sig ) ) {
+ //Kill failed
+ return false;
+ }
+ return true;
+}
+
+bool ProcessesLocal::setNiceness(long pid, int priority) {
+ if ( setpriority( PRIO_PROCESS, pid, priority ) ) {
+ //set niceness failed
+ return false;
+ }
+ return true;
+}
+
+bool ProcessesLocal::setScheduler(long pid, int priorityClass, int priority)
+{
+ if(priorityClass == KSysGuard::Process::Other || priorityClass == KSysGuard::Process::Batch)
+ priority = 0;
+ if(pid <= 0) return false; // check the parameters
+ struct sched_param params;
+ params.sched_priority = priority;
+ switch(priorityClass) {
+ case (KSysGuard::Process::Other):
+ return (sched_setscheduler( pid, SCHED_OTHER, ¶ms) == 0);
+ case (KSysGuard::Process::RoundRobin):
+ return (sched_setscheduler( pid, SCHED_RR, ¶ms) == 0);
+ case (KSysGuard::Process::Fifo):
+ return (sched_setscheduler( pid, SCHED_FIFO, ¶ms) == 0);
+#ifdef SCHED_BATCH
+ case (KSysGuard::Process::Batch):
+ return (sched_setscheduler( pid, SCHED_BATCH, ¶ms) == 0);
+#endif
+ default:
+ return false;
+ }
+}
+
+bool ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority) {
+ return false; //Not yet supported
+}
+
+bool ProcessesLocal::supportsIoNiceness() {
+ return false;
+}
+
+long long ProcessesLocal::totalPhysicalMemory() {
+
+ size_t Total;
+ size_t len;
+ len = sizeof (Total);
+ sysctlbyname("hw.physmem", &Total, &len, NULL, 0);
+ return Total /= 1024;
+}
+
+ProcessesLocal::~ProcessesLocal()
+{
+ delete d;
+}
+
+}
diff --git a/ksysguard/processcore/processes_linux_p.cpp b/ksysguard/processcore/processes_linux_p.cpp
new file mode 100644
index 000000000..1fd6a100b
--- /dev/null
+++ b/ksysguard/processcore/processes_linux_p.cpp
@@ -0,0 +1,517 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 2007 John Tapsell
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "processes_local_p.h"
+#include "process.h"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+//for sysconf
+#include
+//for kill and setNice
+#include
+#include
+#include
+#include
+#include
+//for ionice
+#include
+#include
+//for getsched
+#include
+
+#define PROCESS_BUFFER_SIZE 1000
+
+/* For ionice */
+extern int sys_ioprio_set(int, int, int);
+extern int sys_ioprio_get(int, int);
+
+#define HAVE_IONICE
+/* Check if this system has ionice */
+#if !defined(SYS_ioprio_get) || !defined(SYS_ioprio_set)
+/* All new kernels have SYS_ioprio_get and _set defined, but for the few that do not, here are the definitions */
+#if defined(__i386__)
+#define __NR_ioprio_set 289
+#define __NR_ioprio_get 290
+#elif defined(__ppc__) || defined(__powerpc__)
+#define __NR_ioprio_set 273
+#define __NR_ioprio_get 274
+#elif defined(__x86_64__)
+#define __NR_ioprio_set 251
+#define __NR_ioprio_get 252
+#elif defined(__ia64__)
+#define __NR_ioprio_set 1274
+#define __NR_ioprio_get 1275
+#else
+#ifdef __GNUC__
+#warning "This architecture does not support IONICE. Disabling ionice feature."
+#endif
+#undef HAVE_IONICE
+#endif
+/* Map these to SYS_ioprio_get */
+#define SYS_ioprio_get __NR_ioprio_get
+#define SYS_ioprio_set __NR_ioprio_set
+
+#endif /* !SYS_ioprio_get */
+
+/* Set up ionice functions */
+#ifdef HAVE_IONICE
+#define IOPRIO_WHO_PROCESS 1
+#define IOPRIO_CLASS_SHIFT 13
+
+/* Expose the kernel calls to usespace via syscall
+ * See man ioprio_set and man ioprio_get for information on these functions */
+static int ioprio_set(int which, int who, int ioprio)
+{
+ return syscall(SYS_ioprio_set, which, who, ioprio);
+}
+
+static int ioprio_get(int which, int who)
+{
+ return syscall(SYS_ioprio_get, which, who);
+}
+#endif
+
+
+
+
+namespace KSysGuard
+{
+
+ class ProcessesLocal::Private
+ {
+ public:
+ Private() { mProcDir = opendir( "/proc" );}
+ ~Private();
+ inline bool readProcStatus(long pid, Process *process);
+ inline bool readProcStat(long pid, Process *process);
+ inline bool readProcStatm(long pid, Process *process);
+ inline bool readProcCmdline(long pid, Process *process);
+ inline bool getNiceness(long pid, Process *process);
+ QFile mFile;
+ char mBuffer[PROCESS_BUFFER_SIZE+1]; //used as a buffer to read data into
+ DIR* mProcDir;
+ };
+
+ProcessesLocal::Private::~Private()
+{
+ closedir(mProcDir);
+}
+
+ProcessesLocal::ProcessesLocal() : d(new Private())
+{
+
+}
+
+bool ProcessesLocal::Private::readProcStatus(long pid, Process *process)
+{
+ mFile.setFileName(QString("/proc/%1/status").arg(pid));
+ if(!mFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ return false; /* process has terminated in the meantime */
+
+ process->uid = 0;
+ process->gid = 0;
+ process->tracerpid = 0;
+
+ int size;
+ int found = 0; //count how many fields we found
+ while( (size = mFile.readLine( mBuffer, sizeof(mBuffer))) > 0) { //-1 indicates an error
+ switch( mBuffer[0]) {
+ case 'N':
+ if((unsigned int)size > sizeof("Name:") && qstrncmp(mBuffer, "Name:", sizeof("Name:")-1) == 0) {
+ process->name = QString::fromLocal8Bit(mBuffer + sizeof("Name:")-1, size-sizeof("Name:")+1).trimmed();
+ if(++found == 4) goto finish;
+ }
+ break;
+ case 'U':
+ if((unsigned int)size > sizeof("Uid:") && qstrncmp(mBuffer, "Uid:", sizeof("Uid:")-1) == 0) {
+ sscanf(mBuffer + sizeof("Uid:") -1, "%Ld %Ld %Ld %Ld", &process->uid, &process->euid, &process->suid, &process->fsuid );
+ if(++found == 4) goto finish;
+ }
+ break;
+ case 'G':
+ if((unsigned int)size > sizeof("Gid:") && qstrncmp(mBuffer, "Gid:", sizeof("Gid:")-1) == 0) {
+ sscanf(mBuffer + sizeof("Gid:")-1, "%Ld %Ld %Ld %Ld", &process->gid, &process->egid, &process->sgid, &process->fsgid );
+ if(++found == 4) goto finish;
+ }
+ break;
+ case 'T':
+ if((unsigned int)size > sizeof("TracerPid:") && qstrncmp(mBuffer, "TracerPid:", sizeof("TracerPid:")-1) == 0) {
+ process->tracerpid = atol(mBuffer + sizeof("TracerPid:")-1);
+ if(++found == 4) goto finish;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ finish:
+ mFile.close();
+ return true;
+}
+
+long ProcessesLocal::getParentPid(long pid) {
+ Q_ASSERT(pid != 0);
+ d->mFile.setFileName(QString("/proc/%1/stat").arg(pid));
+ if(!d->mFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ return 0; /* process has terminated in the meantime */
+
+ int size; //amount of data read in
+ if( (size = d->mFile.readLine( d->mBuffer, sizeof(d->mBuffer))) <= 0) { //-1 indicates nothing read
+ d->mFile.close();
+ return 0;
+ }
+
+ d->mFile.close();
+ int current_word = 0;
+ char *word = d->mBuffer;
+
+ while(true) {
+ if(word[0] == ' ' ) {
+ if(++current_word == 3)
+ break;
+ } else if(word[0] == 0) {
+ return 0; //end of data - serious problem
+ }
+ word++;
+ }
+ return atol(++word);
+}
+
+bool ProcessesLocal::Private::readProcStat(long pid, Process *ps)
+{
+ QString filename = QString("/proc/%1/stat").arg(pid);
+ // As an optomization, if the last file read in was stat, then we already have this info in memory
+ if(mFile.fileName() != filename) {
+ mFile.setFileName(filename);
+ if(!mFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ return false; /* process has terminated in the meantime */
+ if( mFile.readLine( mBuffer, sizeof(mBuffer)) <= 0) { //-1 indicates nothing read
+ mFile.close();
+ return false;
+ }
+ mFile.close();
+ }
+
+ int current_word = 0; //count from 0
+ char *word = mBuffer;
+ char status='\0';
+ long vmSize = 0;
+ long vmRSS = 0;
+ while(current_word < 23) {
+ if(word[0] == ' ' ) {
+ ++current_word;
+ switch(current_word) {
+ case 2: //status
+ status=word[1]; // Look at the first letter of the status.
+ // We analyze this after the while loop
+ break;
+ case 6: //ttyNo
+ {
+ int ttyNo = atoi(word+1);
+ int major = ttyNo >> 8;
+ int minor = ttyNo & 0xff;
+ switch(major) {
+ case 136:
+ ps->setTty(QByteArray("pts/") + QByteArray::number(minor));
+ break;
+ case 5:
+ ps->setTty(QByteArray("tty"));
+ case 4:
+ if(minor < 64)
+ ps->setTty(QByteArray("tty") + QByteArray::number(minor));
+ else
+ ps->setTty(QByteArray("ttyS") + QByteArray::number(minor-64));
+ break;
+ default:
+ ps->setTty(QByteArray());
+ }
+ }
+ break;
+ case 13: //userTime
+ ps->setUserTime(atoll(word+1));
+ break;
+ case 14: //sysTime
+ ps->setSysTime(atoll(word+1));
+ break;
+ case 18: //niceLevel
+ ps->setNiceLevel(atoi(word+1)); /*Or should we use getPriority instead? */
+ break;
+ case 22: //vmSize
+ vmSize = atol(word+1);
+ break;
+ case 23: //vmRSS
+ vmRSS = atol(word+1);
+ break;
+ default:
+ break;
+ }
+ } else if(word[0] == 0) {
+ return false; //end of data - serious problem
+ }
+ word++;
+ }
+
+ /* There was a "(ps->vmRss+3) * sysconf(_SC_PAGESIZE)" here in the original ksysguard code. I have no idea why! After comparing it to
+ * meminfo and other tools, this means we report the RSS by 12 bytes differently compared to them. So I'm removing the +3
+ * to be consistent. NEXT TIME COMMENT STRANGE THINGS LIKE THAT! :-) */
+ ps->setVmRSS(vmRSS * sysconf(_SC_PAGESIZE) / 1024); /*convert to KiB*/
+ ps->setVmSize(vmSize /= 1024); /* convert to KiB */
+
+ switch( status) {
+ case 'R':
+ ps->setStatus(Process::Running);
+ break;
+ case 'S':
+ ps->setStatus(Process::Sleeping);
+ break;
+ case 'D':
+ ps->setStatus(Process::DiskSleep);
+ break;
+ case 'Z':
+ ps->setStatus(Process::Zombie);
+ break;
+ case 'T':
+ ps->setStatus(Process::Stopped);
+ break;
+ case 'W':
+ ps->setStatus(Process::Paging);
+ break;
+ default:
+ ps->setStatus(Process::OtherStatus);
+ break;
+ }
+ return true;
+}
+
+bool ProcessesLocal::Private::readProcStatm(long pid, Process *process)
+{
+ mFile.setFileName(QString("/proc/%1/statm").arg(pid));
+ if(!mFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ return false; /* process has terminated in the meantime */
+
+ if( mFile.readLine( mBuffer, sizeof(mBuffer)) <= 0) { //-1 indicates nothing read
+ mFile.close();
+ return 0;
+ }
+ mFile.close();
+
+ int current_word = 0;
+ char *word = mBuffer;
+
+ while(true) {
+ if(word[0] == ' ' ) {
+ if(++current_word == 2) //number of pages that are shared
+ break;
+ } else if(word[0] == 0) {
+ return false; //end of data - serious problem
+ }
+ word++;
+ }
+ long shared = atol(word+1);
+
+ /* we use the rss - shared to find the amount of memory just this app uses */
+ process->vmURSS = process->vmRSS - (shared * sysconf(_SC_PAGESIZE) / 1024);
+ return true;
+}
+
+
+bool ProcessesLocal::Private::readProcCmdline(long pid, Process *process)
+{
+ if(!process->command.isNull()) return true; //only parse the cmdline once
+ mFile.setFileName(QString("/proc/%1/cmdline").arg(pid));
+ if(!mFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ return false; /* process has terminated in the meantime */
+
+ QTextStream in(&mFile);
+ process->command = in.readAll();
+
+ //cmdline seperates parameters with the NULL character
+ process->command.replace('\0', ' ');
+ process->command = process->command.trimmed();
+
+ mFile.close();
+ return true;
+}
+
+bool ProcessesLocal::Private::getNiceness(long pid, Process *process) {
+ int sched = sched_getscheduler(pid);
+ switch(sched) {
+ case (SCHED_OTHER):
+ process->scheduler = KSysGuard::Process::Other;
+ break;
+ case (SCHED_RR):
+ process->scheduler = KSysGuard::Process::RoundRobin;
+ break;
+ case (SCHED_FIFO):
+ process->scheduler = KSysGuard::Process::Fifo;
+ break;
+#ifdef SCHED_BATCH
+ case (SCHED_BATCH):
+ process->scheduler = KSysGuard::Process::Batch;
+ break;
+#endif
+ default:
+ process->scheduler = KSysGuard::Process::Other;
+ }
+ if(sched == SCHED_FIFO || sched == SCHED_RR) {
+ struct sched_param param;
+ if(sched_getparam(pid, ¶m) == 0)
+ process->niceLevel = param.sched_priority;
+ else
+ process->niceLevel = 0; //Error getting scheduler parameters.
+ }
+
+#ifdef HAVE_IONICE
+ int ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid); /* Returns from 0 to 7 for the iopriority, and -1 if there's an error */
+ if(ioprio == -1) {
+ process->ioniceLevel = -1;
+ process->ioPriorityClass = KSysGuard::Process::None;
+ return false; /* Error. Just give up. */
+ }
+ process->ioniceLevel = ioprio & 0xff; /* Bottom few bits are the priority */
+ process->ioPriorityClass = (KSysGuard::Process::IoPriorityClass)(ioprio >> IOPRIO_CLASS_SHIFT); /* Top few bits are the class */
+#else
+ return false; /* Do nothing, if we do not support this architecture */
+#endif
+ return true;
+}
+
+bool ProcessesLocal::updateProcessInfo( long pid, Process *process)
+{
+ if(!d->readProcStat(pid, process)) return false;
+ if(!d->readProcStatus(pid, process)) return false;
+ if(!d->readProcStatm(pid, process)) return false;
+ if(!d->readProcCmdline(pid, process)) return false;
+ if(!d->getNiceness(pid, process)) return false;
+
+ return true;
+}
+
+QSet ProcessesLocal::getAllPids( )
+{
+ QSet pids;
+ if(d->mProcDir==NULL) return pids; //There's not much we can do without /proc
+ struct dirent* entry;
+ rewinddir(d->mProcDir);
+ while ( ( entry = readdir( d->mProcDir ) ) )
+ if ( entry->d_name[ 0 ] >= '0' && entry->d_name[ 0 ] <= '9' )
+ pids.insert(atol( entry->d_name ));
+ return pids;
+}
+
+bool ProcessesLocal::sendSignal(long pid, int sig) {
+ if ( kill( (pid_t)pid, sig ) ) {
+ //Kill failed
+ return false;
+ }
+ return true;
+}
+
+bool ProcessesLocal::setNiceness(long pid, int priority) {
+ if(pid <= 0) return false; // check the parameters
+ if ( setpriority( PRIO_PROCESS, pid, priority ) ) {
+ //set niceness failed
+ return false;
+ }
+ return true;
+}
+
+bool ProcessesLocal::setScheduler(long pid, int priorityClass, int priority) {
+ if(priorityClass == KSysGuard::Process::Other || priorityClass == KSysGuard::Process::Batch)
+ priority = 0;
+ if(pid <= 0) return false; // check the parameters
+ struct sched_param params;
+ params.sched_priority = priority;
+ switch(priorityClass) {
+ case (KSysGuard::Process::Other):
+ return (sched_setscheduler( pid, SCHED_OTHER, ¶ms) == 0);
+ case (KSysGuard::Process::RoundRobin):
+ return (sched_setscheduler( pid, SCHED_RR, ¶ms) == 0);
+ case (KSysGuard::Process::Fifo):
+ return (sched_setscheduler( pid, SCHED_FIFO, ¶ms) == 0);
+#ifdef SCHED_BATCH
+ case (KSysGuard::Process::Batch):
+ return (sched_setscheduler( pid, SCHED_BATCH, ¶ms) == 0);
+#endif
+ default:
+ return false;
+ }
+}
+
+
+bool ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority) {
+#ifdef HAVE_IONICE
+ if (ioprio_set(IOPRIO_WHO_PROCESS, pid, priority | priorityClass << IOPRIO_CLASS_SHIFT) == -1) {
+ //set io niceness failed
+ return false;
+ }
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool ProcessesLocal::supportsIoNiceness() {
+#ifdef HAVE_IONICE
+ return true;
+#else
+ return false;
+#endif
+}
+
+long long ProcessesLocal::totalPhysicalMemory() {
+ //Try to get the memory via sysconf. Note the cast to long long to try to avoid a long overflow
+ //Should we use sysconf(_SC_PAGESIZE) or getpagesize() ?
+ long long memory = ((long long)sysconf(_SC_PHYS_PAGES)) * (sysconf(_SC_PAGESIZE)/1024);
+ if(memory > 0) return memory;
+
+ //This is backup code incase the above failed. It should never fail on a linux system.
+
+ d->mFile.setFileName("/proc/meminfo");
+ if(!d->mFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ return 0;
+
+ int size;
+ while( (size = d->mFile.readLine( d->mBuffer, sizeof(d->mBuffer))) > 0) { //-1 indicates an error
+ switch( d->mBuffer[0]) {
+ case 'M':
+ if((unsigned int)size > sizeof("MemTotal:") && qstrncmp(d->mBuffer, "MemTotal:", sizeof("MemTotal:")-1) == 0) {
+ d->mFile.close();
+ return atoll(d->mBuffer + sizeof("MemTotal:")-1);
+ }
+ }
+ }
+ return 0; // Not found. Probably will never happen
+}
+ProcessesLocal::~ProcessesLocal()
+{
+ delete d;
+}
+
+}
diff --git a/ksysguard/processcore/processes_local_p.cpp b/ksysguard/processcore/processes_local_p.cpp
new file mode 100644
index 000000000..5ab9fb579
--- /dev/null
+++ b/ksysguard/processcore/processes_local_p.cpp
@@ -0,0 +1,37 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 2007 John Tapsell
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#if defined __linux__
+#include "processes_linux_p.cpp"
+#elif defined __FreeBSD__ || defined __DragonFly__
+#include "processes_freebsd_p.cpp"
+#elif defined __OpenBSD__
+#include "processes_openbsd_p.cpp"
+#elif defined __NetBSD__
+#include "processes_netbsd_p.cpp"
+#else
+// Use Qt's OS detection
+#include
+#ifdef Q_OS_SOLARIS
+#include "processes_solaris_p.cpp"
+#endif
+#endif
+
diff --git a/ksysguard/processcore/processes_local_p.h b/ksysguard/processcore/processes_local_p.h
new file mode 100644
index 000000000..202f4bf7d
--- /dev/null
+++ b/ksysguard/processcore/processes_local_p.h
@@ -0,0 +1,70 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 2007 John Tapsell
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef PROCESSES_LOCAL_H_
+#define PROCESSES_LOCAL_H_
+
+#include "processes_base_p.h"
+#include //For sysconf
+
+
+#include
+
+namespace KSysGuard
+{
+ class Process;
+
+ /**
+ * This is the OS specific code to get process information for the local host.
+ */
+ class ProcessesLocal : public AbstractProcesses {
+ public:
+ ProcessesLocal();
+ virtual ~ProcessesLocal();
+ virtual QSet getAllPids();
+ virtual long getParentPid(long pid);
+ virtual bool updateProcessInfo(long pid, Process *process);
+ virtual bool sendSignal(long pid, int sig);
+ virtual bool setNiceness(long pid, int priority);
+ virtual bool setScheduler(long pid, int priorityClass, int priority);
+ virtual long long totalPhysicalMemory();
+ virtual bool setIoNiceness(long pid, int priorityClass, int priority);
+ virtual bool supportsIoNiceness();
+ virtual long numberProcessorCores()
+#ifdef _SC_NPROCESSORS_ONLN
+ { return sysconf(_SC_NPROCESSORS_ONLN); } // Should work on any recent posix system
+#else
+ ;
+#endif
+ virtual void updateAllProcesses() { emit processesUpdated(); } //For local machine, there is no delay
+
+ private:
+ /**
+ * You can use this for whatever data you want. Be careful about preserving state in between getParentPid and updateProcessInfo calls
+ * if you chose to do that. getParentPid may be called several times for different pids before the relevant updateProcessInfo calls are made.
+ * This is because the tree structure has to be sorted out first.
+ */
+ class Private;
+ Private *d;
+
+ };
+}
+#endif
diff --git a/ksysguard/processcore/processes_netbsd_p.cpp b/ksysguard/processcore/processes_netbsd_p.cpp
new file mode 100644
index 000000000..7996f0337
--- /dev/null
+++ b/ksysguard/processcore/processes_netbsd_p.cpp
@@ -0,0 +1,292 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Manolo Valdes
+ Copyright (C) 2007 Mark Davies
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "processes_local_p.h"
+#include "process.h"
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+
+namespace KSysGuard
+{
+
+ class ProcessesLocal::Private
+ {
+ public:
+ Private() { kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");}
+ ~Private() { kvm_close(kd);}
+ inline bool readProc(long pid, struct kinfo_proc2 **p, int *num);
+ inline void readProcStatus(struct kinfo_proc2 *p, Process *process);
+ inline void readProcStat(struct kinfo_proc2 *p, Process *process);
+ inline void readProcStatm(struct kinfo_proc2 *p, Process *process);
+ inline bool readProcCmdline(struct kinfo_proc2 *p, Process *process);
+
+ kvm_t *kd;
+ };
+
+#ifndef _SC_NPROCESSORS_ONLN
+long int KSysGuard::ProcessesLocal::numberProcessorCores()
+{
+ int mib[2];
+ int ncpu;
+ size_t len;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ len = sizeof(ncpu);
+
+ if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1 || !len)
+ return 1;
+ return len;
+}
+#endif
+
+bool ProcessesLocal::Private::readProc(long pid, struct kinfo_proc2 **p, int *num)
+{
+ int len;
+ int op, arg;
+
+ if (pid == 0) {
+ op = KERN_PROC_ALL;
+ arg = 0;
+ } else {
+ op = KERN_PROC_PID;
+ arg = pid;
+ }
+ *p = kvm_getproc2(kd, op, arg, sizeof(struct kinfo_proc2), &len);
+
+ if (len < 1)
+ return false;
+
+ if (num != NULL)
+ *num = len;
+ return true;
+}
+
+void ProcessesLocal::Private::readProcStatus(struct kinfo_proc2 *p, Process *process)
+{
+ process->setUid(p->p_ruid);
+ process->setEuid(p->p_uid);
+ process->setGid(p->p_rgid);
+ process->setEgid(p->p_gid);
+ process->setTracerpid(0);
+
+ process->setName(QString(p->p_comm ? p->p_comm : "????"));
+}
+
+void ProcessesLocal::Private::readProcStat(struct kinfo_proc2 *p, Process *ps)
+{
+ const char *ttname;
+ dev_t dev;
+
+ ps->setUserTime(p->p_uutime_sec*100+p->p_uutime_usec/10000);
+ ps->setSysTime(p->p_ustime_sec*100+p->p_ustime_usec/10000);
+
+ ps->setUserUsage(100.0 * ((double)(p->p_pctcpu) / FSCALE));
+ ps->setSysUsage(0);
+
+ ps->setNiceLevel(p->p_nice - NZERO);
+ ps->setVmSize((p->p_vm_tsize + p->p_vm_dsize + p->p_vm_ssize)
+ * getpagesize());
+ ps->setVmRSS(p->p_vm_rssize * getpagesize());
+
+// "idle","run","sleep","stop","zombie"
+ switch( p->p_stat ) {
+ case LSRUN:
+ ps->setStatus(Process::Running);
+ break;
+ case LSSLEEP:
+ ps->setStatus(Process::Sleeping);
+ break;
+ case LSSTOP:
+ ps->setStatus(Process::Stopped);
+ break;
+ case LSZOMB:
+ ps->setStatus(Process::Zombie);
+ break;
+ case LSONPROC:
+ ps->setStatus(Process::Running);
+ break;
+ default:
+ ps->setStatus(Process::OtherStatus);
+ break;
+ }
+
+ dev = p->p_tdev;
+ if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
+ ps->setTty(QByteArray());
+ } else {
+ ps->setTty(QByteArray(ttname));
+ }
+}
+
+void ProcessesLocal::Private::readProcStatm(struct kinfo_proc2 *p, Process *process)
+{
+// TODO
+
+// unsigned long shared;
+// process->vmURSS = process->vmRSS - (shared * sysconf(_SC_PAGESIZE) / 1024);
+ process->setVmURSS(-1);
+}
+
+bool ProcessesLocal::Private::readProcCmdline(struct kinfo_proc2 *p, Process *process)
+{
+ char **argv;
+
+ if ((argv = kvm_getargv2(kd, p, 256)) == NULL)
+ return false;
+
+ QString command = QString("");
+
+ while (*argv) {
+ command += *argv;
+ command += " ";
+ argv++;
+ }
+ process->setCommand(command.trimmed());
+
+ return true;
+}
+
+ProcessesLocal::ProcessesLocal() : d(new Private())
+{
+
+}
+
+long ProcessesLocal::getParentPid(long pid) {
+ long long ppid = 0;
+ struct kinfo_proc2 *p;
+ if(d->readProc(pid, &p, 0))
+ {
+ ppid = p->p_ppid;
+ }
+ return ppid;
+}
+
+bool ProcessesLocal::updateProcessInfo( long pid, Process *process)
+{
+ struct kinfo_proc2 *p;
+ if(!d->readProc(pid, &p, NULL)) return false;
+ d->readProcStat(p, process);
+ d->readProcStatus(p, process);
+ d->readProcStatm(p, process);
+ if(!d->readProcCmdline(p, process)) return false;
+
+ return true;
+}
+
+QSet ProcessesLocal::getAllPids( )
+{
+ QSet pids;
+ int len;
+ int num;
+ struct kinfo_proc2 *p;
+
+ d->readProc(0, &p, &len);
+
+ for (num = 0; num < len; num++)
+ {
+ long pid = p[num].p_pid;
+ long long ppid = p[num].p_ppid;
+
+ //skip all process with parent id = 0 but init
+ if(ppid == 0 && pid != 1)
+ continue;
+ pids.insert(pid);
+ }
+ return pids;
+}
+
+bool ProcessesLocal::sendSignal(long pid, int sig) {
+ if ( kill( (pid_t)pid, sig ) ) {
+ //Kill failed
+ return false;
+ }
+ return true;
+}
+
+bool ProcessesLocal::setNiceness(long pid, int priority) {
+ if ( setpriority( PRIO_PROCESS, pid, priority ) ) {
+ //set niceness failed
+ return false;
+ }
+ return true;
+}
+
+bool ProcessesLocal::setScheduler(long pid, int priorityClass, int priority)
+{
+ if(priorityClass == KSysGuard::Process::Other || priorityClass == KSysGuard::Process::Batch)
+ priority = 0;
+ if(pid <= 0) return false; // check the parameters
+ struct sched_param params;
+ params.sched_priority = priority;
+ switch(priorityClass) {
+ case (KSysGuard::Process::Other):
+ return (sched_setscheduler( pid, SCHED_OTHER, ¶ms) == 0);
+ case (KSysGuard::Process::RoundRobin):
+ return (sched_setscheduler( pid, SCHED_RR, ¶ms) == 0);
+ case (KSysGuard::Process::Fifo):
+ return (sched_setscheduler( pid, SCHED_FIFO, ¶ms) == 0);
+#ifdef SCHED_BATCH
+ case (KSysGuard::Process::Batch):
+ return (sched_setscheduler( pid, SCHED_BATCH, ¶ms) == 0);
+#endif
+ default:
+ return false;
+ }
+}
+
+bool ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority) {
+ return false; //Not yet supported
+}
+
+bool ProcessesLocal::supportsIoNiceness() {
+ return false;
+}
+
+long long ProcessesLocal::totalPhysicalMemory() {
+
+ size_t Total;
+ size_t len;
+ len = sizeof (Total);
+ sysctlbyname("hw.physmem", &Total, &len, NULL, 0);
+ return Total /= 1024;
+}
+
+ProcessesLocal::~ProcessesLocal()
+{
+ delete d;
+}
+
+}
diff --git a/ksysguard/processcore/processes_openbsd_p.cpp b/ksysguard/processcore/processes_openbsd_p.cpp
new file mode 100644
index 000000000..87e55fa52
--- /dev/null
+++ b/ksysguard/processcore/processes_openbsd_p.cpp
@@ -0,0 +1,306 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Manolo Valdes
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "processes_local_p.h"
+#include "process.h"
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#if defined(__DragonFly__)
+#include
+#include
+#endif
+#include
+#include
+#include
+
+
+
+
+namespace KSysGuard
+{
+
+ class ProcessesLocal::Private
+ {
+ public:
+ Private() {;}
+ ~Private() {;}
+ inline bool readProc(long pid, struct kinfo_proc *p);
+ inline void readProcStatus(struct kinfo_proc *p, Process *process);
+ inline void readProcStat(struct kinfo_proc *p, Process *process);
+ inline void readProcStatm(struct kinfo_proc *p, Process *process);
+ inline bool readProcCmdline(long pid, Process *process);
+ };
+
+bool ProcessesLocal::Private::readProc(long pid, struct kinfo_proc *p)
+{
+ int mib[4];
+ size_t len;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = pid;
+
+ len = sizeof (struct kinfo_proc);
+ if (sysctl(mib, 4, p, &len, NULL, 0) == -1 || !len)
+ return false;
+ return true;
+}
+
+void ProcessesLocal::Private::readProcStatus(struct kinfo_proc *p, Process *process)
+{
+ process->setUid(0);
+ process->setGid(0);
+ process->setTracerpid(0);
+
+
+#if defined(__FreeBSD__) && __FreeBSD_version >= 500015
+ process->setUid(p->ki_uid);
+ process->setGid(p->ki_pgid);
+ process->setName(QString(p->ki_comm ? p->ki_comm : "????"));
+#elif defined(__DragonFly__) && __DragonFly_version >= 190000
+ process->setUid(p->kp_uid);
+ process->setGid(p->kp_pgid);
+ process->setName(QString(p->kp_comm ? p->kp_comm : "????"));
+#else
+ process->setUid(p->kp_eproc.e_ucred.cr_uid);
+ process->setGid(p->kp_eproc.e_pgid);
+#endif
+}
+
+void ProcessesLocal::Private::readProcStat(struct kinfo_proc *p, Process *ps)
+{
+ int status;
+ struct rusage pru;
+#if defined(__FreeBSD__) && __FreeBSD_version >= 500015
+ ps->setUserTime(p->ki_runtime / 10000);
+ ps->setNiceLevel(p->ki_nice);
+ ps->setVmSize(p->ki_size);
+ ps->setVmRSS(p->ki_rssize * getpagesize());
+ status = p->ki_stat;
+#elif defined(__DragonFly__) && __DragonFly_version >= 190000
+ if (!getrusage(p->kp_pid, &pru)) {
+ errx(1, "failed to get rusage info");
+ }
+ ps->setUserTime(pru.ru_utime.tv_usec / 1000); /*p_runtime / 1000*/
+ ps->setNiceLevel(p->kp_nice);
+ ps->setVmSize(p->kp_vm_map_size);
+ ps->setVmRSS(p->kp_vm_rssize * getpagesize());
+ status = p->kp_stat;
+#else
+ ps->setUserTime(p->kp_proc.p_rtime.tv_sec*100+p->kp_proc.p_rtime.tv_usec/100);
+ ps->setNiceLevel(p->kp_proc.p_nice);
+ ps->setVmSize(p->kp_eproc.e_vm.vm_map.size);
+ ps->setVmRSS(p->kp_eproc.e_vm.vm_rssize * getpagesize());
+ status = p->kp_proc.p_stat;
+#endif
+ ps->setSysTime(0);
+
+// "idle","run","sleep","stop","zombie"
+ switch( status ) {
+ case '0':
+ ps->setStatus(Process::DiskSleep);
+ break;
+ case '1':
+ ps->setStatus(Process::Running);
+ break;
+ case '2':
+ ps->setStatus(Process::Sleeping);
+ break;
+ case '3':
+ ps->setStatus(Process::Stopped);
+ break;
+ case '4':
+ ps->setStatus(Process::Zombie);
+ break;
+ default:
+ ps->setStatus(Process::OtherStatus);
+ break;
+ }
+}
+
+void ProcessesLocal::Private::readProcStatm(struct kinfo_proc *p, Process *process)
+{
+// TODO
+
+// unsigned long shared;
+// process->setVmURSS(process->vmRSS - (shared * sysconf(_SC_PAGESIZE) / 1024));
+}
+
+bool ProcessesLocal::Private::readProcCmdline(long pid, Process *process)
+{
+ int mib[4];
+ struct kinfo_proc p;
+ size_t buflen = 256;
+ char buf[256];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_ARGS;
+ mib[3] = pid;
+
+ if (sysctl(mib, 4, buf, &buflen, NULL, 0) == -1 || !buflen)
+ return false;
+ QString command = QString(buf);
+
+ //cmdline seperates parameters with the NULL character
+ command.replace('\0', ' ');
+ process->setCommand(command.trimmed());
+
+ return true;
+}
+
+ProcessesLocal::ProcessesLocal() : d(new Private())
+{
+
+}
+
+long ProcessesLocal::getParentPid(long pid) {
+ Q_ASSERT(pid != 0);
+ long long ppid = 0;
+ struct kinfo_proc p;
+ if(d->readProc(pid, &p))
+ {
+#if defined(__FreeBSD__) && __FreeBSD_version >= 500015
+ ppid = p.ki_ppid;
+#elif defined(__DragonFly__) && __DragonFly_version >= 190000
+ ppid = p.kp_ppid;
+#else
+ ppid = p.kp_eproc.e_ppid;
+#endif
+ }
+ return ppid;
+}
+
+bool ProcessesLocal::updateProcessInfo( long pid, Process *process)
+{
+ struct kinfo_proc p;
+ if(!d->readProc(pid, &p)) return false;
+ d->readProcStat(&p, process);
+ d->readProcStatus(&p, process);
+ d->readProcStatm(&p, process);
+ if(!d->readProcCmdline(pid, process)) return false;
+
+ return true;
+}
+
+QSet ProcessesLocal::getAllPids( )
+{
+ QSet pids;
+ int mib[3];
+ size_t len;
+ size_t num;
+ struct kinfo_proc *p;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_ALL;
+ sysctl(mib, 3, NULL, &len, NULL, 0);
+ p = (kinfo_proc *) malloc(len);
+ sysctl(mib, 3, p, &len, NULL, 0);
+
+ for (num = 0; num < len / sizeof(struct kinfo_proc); num++)
+#if defined(__FreeBSD__) && __FreeBSD_version >= 500015
+ pids.insert(p[num].ki_pid);
+#elif defined(__DragonFly__) && __DragonFly_version >= 190000
+ pids.insert(p[num].kp_pid);
+#else
+ pids.insert(p[num].kp_proc.p_pid);
+#endif
+ free(p);
+ return pids;
+}
+
+bool ProcessesLocal::sendSignal(long pid, int sig) {
+ if ( kill( (pid_t)pid, sig ) ) {
+ //Kill failed
+ return false;
+ }
+ return true;
+}
+
+bool ProcessesLocal::setNiceness(long pid, int priority) {
+ if ( setpriority( PRIO_PROCESS, pid, priority ) ) {
+ //set niceness failed
+ return false;
+ }
+ return true;
+}
+
+bool ProcessesLocal::setScheduler(long pid, int priorityClass, int priority)
+{
+ if(priorityClass == KSysGuard::Process::Other || priorityClass == KSysGuard::Process::Batch)
+ priority = 0;
+ if(pid <= 0) return false; // check the parameters
+ return false;
+}
+
+bool ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority) {
+ return false; //Not yet supported
+}
+
+bool ProcessesLocal::supportsIoNiceness() {
+ return false;
+}
+
+long long ProcessesLocal::totalPhysicalMemory() {
+
+ static int physmem_mib[] = { CTL_HW, HW_PHYSMEM };
+ /* get the page size with "getpagesize" and calculate pageshift from
+ * it */
+ int pagesize = ::getpagesize();
+ int pageshift = 0;
+ while (pagesize > 1) {
+ pageshift++;
+ pagesize >>= 1;
+ }
+ size_t Total = 0;
+ size_t size = sizeof(Total);
+ sysctl(physmem_mib, 2, &Total, &size, NULL, 0);
+ return Total /= 1024;
+}
+
+long int KSysGuard::ProcessesLocal::numberProcessorCores()
+{
+ int mib[2];
+ int ncpu;
+ size_t len;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ len = sizeof(ncpu);
+
+ if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1 || !len)
+ return 1;
+ return len;
+}
+ProcessesLocal::~ProcessesLocal()
+{
+ delete d;
+}
+
+}
diff --git a/ksysguard/processcore/processes_remote_p.cpp b/ksysguard/processcore/processes_remote_p.cpp
new file mode 100644
index 000000000..eb5e096a5
--- /dev/null
+++ b/ksysguard/processcore/processes_remote_p.cpp
@@ -0,0 +1,267 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 2007 John Tapsell
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "processes_remote_p.h"
+#include "process.h"
+
+#include
+#include
+#include
+
+#include
+#include
+
+
+
+
+
+namespace KSysGuard
+{
+
+ class ProcessesRemote::Private
+ {
+ public:
+ Private() {havePsInfo = false; pidColumn = 1;
+ ppidColumn = nameColumn = uidColumn = gidColumn =
+ statusColumn = userColumn = systemColumn = niceColumn =
+ vmSizeColumn = vmRSSColumn = loginColumn = commandColumn =
+ tracerPidColumn = ttyColumn = ioprioClassColumn = ioprioColumn =
+ vmURSSColumn = -1;
+ usedMemory = freeMemory;}
+ ~Private() {;}
+ QString host;
+ QList lastAnswer;
+ QSet pids;
+ QHash > processByPid;
+
+ bool havePsInfo;
+ int pidColumn;
+ int ppidColumn;
+ int tracerPidColumn;
+ int nameColumn;
+ int uidColumn;
+ int gidColumn;
+ int statusColumn;
+ int userColumn;
+ int systemColumn;
+ int niceColumn;
+ int vmSizeColumn;
+ int vmRSSColumn;
+ int vmURSSColumn;
+ int loginColumn;
+ int commandColumn;
+ int ioprioClassColumn;
+ int ioprioColumn;
+ int ttyColumn;
+
+ int numColumns;
+
+ long freeMemory;
+ long usedMemory;
+
+ };
+ProcessesRemote::ProcessesRemote(const QString &hostname) : d(new Private())
+{
+ d->host = hostname;
+ QTimer::singleShot(0, this, SLOT(setup()));
+}
+
+void ProcessesRemote::setup() {
+ emit runCommand("mem/physical/used", (int)UsedMemory);
+ emit runCommand("mem/physical/free", (int)FreeMemory);
+ emit runCommand("ps?", (int)PsInfo);
+ emit runCommand("ps", (int)Ps);
+}
+
+
+long ProcessesRemote::getParentPid(long pid) {
+ if(!d->processByPid.contains(pid)) {
+ kDebug() << "Parent pid requested for pid that we do not have info on " << pid;
+ return 0;
+ }
+ if(d->ppidColumn == -1) {
+ kDebug() << "ppid column not known ";
+ return 0;
+ }
+ return d->processByPid[pid].at(d->ppidColumn).toLong();
+}
+bool ProcessesRemote::updateProcessInfo( long pid, Process *process)
+{
+ Q_CHECK_PTR(process);
+ if(!d->processByPid.contains(pid)) {
+ kDebug() << "update request for pid that we do not have info on " << pid;
+ return false;
+ }
+ QList p = d->processByPid[pid];
+
+ if(d->nameColumn!= -1) process->setName(p.at(d->nameColumn));
+ if(d->uidColumn!= -1) process->setUid(p.at(d->uidColumn).toLong());
+ if(d->gidColumn!= -1) process->setGid(p.at(d->gidColumn).toLong());
+ if(d->statusColumn!= -1) {
+ switch( p.at(d->statusColumn)[0] ) {
+ case 's':
+ process->setStatus(Process::Sleeping);
+ break;
+ case 'r':
+ process->setStatus(Process::Running);
+ break;
+ }
+ }
+ if(d->userColumn!= -1) process->setUserTime(p.at(d->userColumn).toLong());
+ if(d->systemColumn!= -1) process->setSysTime(p.at(d->systemColumn).toLong());
+ if(d->niceColumn!= -1) process->setNiceLevel(p.at(d->niceColumn).toLong());
+ if(d->vmSizeColumn!= -1) process->setVmSize(p.at(d->vmSizeColumn).toLong());
+ if(d->vmRSSColumn!= -1) process->setVmRSS(p.at(d->vmRSSColumn).toLong());
+ if(d->vmURSSColumn!= -1) process->setVmURSS(p.at(d->vmURSSColumn).toLong());
+ if(d->loginColumn!= -1) process->setLogin(QString::fromUtf8(p.at(d->loginColumn).data()));
+ if(d->commandColumn!= -1) process->setCommand(QString::fromUtf8(p.at(d->commandColumn).data()));
+ if(d->tracerPidColumn!= -1) process->setTracerpid(p.at(d->tracerPidColumn).toLong());
+ if(d->vmURSSColumn!= -1) process->setVmURSS(p.at(d->vmURSSColumn).toLong());
+ if(d->ttyColumn!= -1) process->setTty(p.at(d->ttyColumn));
+ if(d->ioprioColumn!= -1) process->setIoniceLevel(p.at(d->ioprioColumn).toInt());
+ if(d->ioprioClassColumn!= -1) process->setIoPriorityClass((KSysGuard::Process::IoPriorityClass)(p.at(d->ioprioClassColumn).toInt()));
+
+ return true;
+}
+
+void ProcessesRemote::updateAllProcesses()
+{
+ if(!d->havePsInfo)
+ emit runCommand("ps?", (int)PsInfo);
+ emit runCommand("ps", (int)Ps);
+}
+QSet ProcessesRemote::getAllPids( )
+{
+ d->pids.clear();
+ d->processByPid.clear();
+ foreach(const QByteArray &process, d->lastAnswer) {
+ QList info = process.split('\t');
+ if(info.size() == d->numColumns) {
+ int pid = info.at(d->pidColumn).toLong();
+ Q_ASSERT(! d->pids.contains(pid));
+ d->pids << pid;
+ d->processByPid[pid] = info;
+ }
+ }
+ return d->pids;
+}
+
+bool ProcessesRemote::sendSignal(long pid, int sig) {
+ //TODO run the proper command for all these functions below
+ emit runCommand("kill " + QString::number(pid) + " " + QString::number(sig), (int)Kill);
+ return true;
+}
+bool ProcessesRemote::setNiceness(long pid, int priority) {
+ emit runCommand("setpriority " + QString::number(pid) + " " + QString::number(priority), (int)Renice);
+ return true;
+}
+
+bool ProcessesRemote::setIoNiceness(long pid, int priorityClass, int priority) {
+ emit runCommand("ionice " + QString::number(pid) + " " + QString::number(priorityClass) + " " + QString::number(priority), (int)Ionice);
+ return true;
+}
+
+bool ProcessesRemote::setScheduler(long pid, int priorityClass, int priority) {
+ return false;
+}
+
+bool ProcessesRemote::supportsIoNiceness() {
+ return true;
+}
+
+long long ProcessesRemote::totalPhysicalMemory() {
+ return d->usedMemory + d->freeMemory;
+}
+long ProcessesRemote::numberProcessorCores() {
+ return 0;
+}
+
+void ProcessesRemote::answerReceived( int id, const QList& answer ) {
+ switch (id) {
+ case PsInfo: {
+ if(answer.isEmpty()) return; //Invalid data
+ QList info = answer.at(0).split('\t');
+ d->numColumns = info.size();
+ for(int i =0; i < d->numColumns; i++) {
+ if(info[i] == "Name")
+ d->nameColumn = i;
+ else if(info[i] == "PID")
+ d->pidColumn = i;
+ else if(info[i] == "PPID")
+ d->ppidColumn = i;
+ else if(info[i] == "UID")
+ d->uidColumn = i;
+ else if(info[i] == "GID")
+ d->gidColumn = i;
+ else if(info[i] == "TracerPID")
+ d->tracerPidColumn = i;
+ else if(info[i] == "Status")
+ d->statusColumn = i;
+ else if(info[i] == "User Time")
+ d->userColumn = i;
+ else if(info[i] == "System Time")
+ d->systemColumn = i;
+ else if(info[i] == "Nice")
+ d->niceColumn = i;
+ else if(info[i] == "VmSize")
+ d->vmSizeColumn = i;
+ else if(info[i] == "VmRss")
+ d->vmRSSColumn = i;
+ else if(info[i] == "VmURss")
+ d->vmURSSColumn = i;
+ else if(info[i] == "Login")
+ d->loginColumn = i;
+ else if(info[i] == "TTY")
+ d->ttyColumn = i;
+ else if(info[i] == "Command")
+ d->commandColumn = i;
+ else if(info[i] == "IO Priority Class")
+ d->ioprioClassColumn = i;
+ else if(info[i] == "IO Priority")
+ d->ioprioColumn = i;
+ }
+ d->havePsInfo = true;
+ break;
+ }
+ case Ps:
+ d->lastAnswer = answer;
+ if(!d->havePsInfo) return; //Not setup yet. Should never happen
+ emit processesUpdated();
+ case FreeMemory:
+ if(answer.isEmpty()) return; //Invalid data
+ d->freeMemory = answer[0].toLong();
+ break;
+ case UsedMemory:
+ if(answer.isEmpty()) return; //Invalid data
+ d->usedMemory = answer[0].toLong();
+ break;
+ }
+
+}
+
+ProcessesRemote::~ProcessesRemote()
+{
+ delete d;
+}
+
+}
+
+#include "processes_remote_p.moc"
+
diff --git a/ksysguard/processcore/processes_remote_p.h b/ksysguard/processcore/processes_remote_p.h
new file mode 100644
index 000000000..40ac620ed
--- /dev/null
+++ b/ksysguard/processcore/processes_remote_p.h
@@ -0,0 +1,78 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 2007 John Tapsell
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef PROCESSES_REMOTE_P_H_
+#define PROCESSES_REMOTE_P_H_
+
+#include "processes_base_p.h"
+#include
+class Process;
+namespace KSysGuard
+{
+ /**
+ * This is used to connect to a remote host
+ */
+ class ProcessesRemote : public AbstractProcesses {
+ Q_OBJECT
+ public:
+ ProcessesRemote(const QString &hostname);
+ virtual ~ProcessesRemote();
+ virtual QSet getAllPids();
+ virtual long getParentPid(long pid);
+ virtual bool updateProcessInfo(long pid, Process *process);
+ virtual bool sendSignal(long pid, int sig);
+ virtual bool setNiceness(long pid, int priority);
+ virtual bool setScheduler(long pid, int priorityClass, int priority);
+ virtual long long totalPhysicalMemory();
+ virtual bool setIoNiceness(long pid, int priorityClass, int priority);
+ virtual bool supportsIoNiceness();
+ virtual long numberProcessorCores();
+ virtual void updateAllProcesses();
+
+
+ Q_SIGNALS:
+ /** For a remote machine, we rely on being able to communicate with ksysguardd.
+ * This must be dealt with by the program including this widget. It must listen to our
+ * 'runCommand' signal, and run the given command, with the given id. */
+ void runCommand(const QString &command, int id);
+
+ public Q_SLOTS:
+ /** For a remote machine, we rely on being able to communicate with ksysguardd.
+ * The programming using this must call this slot when an answer is received from ksysguardd,
+ * in response to a runCommand request. The id identifies the answer */
+ void answerReceived( int id, const QList& answer );
+ /** Called soon after */
+ void setup();
+
+ protected:
+ enum { PsInfo, Ps, UsedMemory, FreeMemory, Kill, Renice, Ionice };
+
+ private:
+ /**
+ * You can use this for whatever data you want. Be careful about preserving state in between getParentPid and updateProcessInfo calls
+ * if you chose to do that. getParentPid may be called several times for different pids before the relevant updateProcessInfo calls are made.
+ * This is because the tree structure has to be sorted out first.
+ */
+ class Private;
+ Private *d;
+
+ };
+}
+#endif
diff --git a/ksysguard/processcore/processes_solaris_p.cpp b/ksysguard/processcore/processes_solaris_p.cpp
new file mode 100644
index 000000000..c3b0566a3
--- /dev/null
+++ b/ksysguard/processcore/processes_solaris_p.cpp
@@ -0,0 +1,100 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Adriaan de Groot
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "processes_local_p.h"
+#include "process.h"
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include