bum-de-dum! plasma to kdelibs.
svn path=/trunk/KDE/kdelibs/; revision=879757
This commit is contained in:
parent
8a4bc36925
commit
fa5a2d87d9
311
CMakeLists.txt
311
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)
|
||||
|
104
Mainpage.dox
104
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.
|
||||
<p>
|
||||
The following libraries are available:
|
||||
- <a href="../plasma/html/index.html">libplasma</a>, a library for implementing
|
||||
%Plasma applets and data engines
|
||||
- <a href="../kworkspace/html/index.html">libkworkspace</a>, a library for
|
||||
interacting with the workspace
|
||||
|
||||
The <a href="http://doc.trolltech.com/latest/graphicsview.html">Qt Graphics View
|
||||
framework</a> and the <a href="http://api.kde.org/4.x-api/kdelibs-apidocs/">KDE
|
||||
libraries</a> 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.
|
||||
<a href="http://amarok.kde.org">Amarok</a> 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
|
||||
<a href="http://doc.trolltech.com/latest/model-view-programming.html">Model /
|
||||
View framework</a> 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
|
||||
<a href="http://techbase.kde.org/Development/Tutorials/Plasma">Plasma tutorials</a>
|
||||
on TechBase provide a good introduction to writing plugins, such as widgets and
|
||||
data engines, for libplasma-based applications.
|
||||
|
||||
@authors
|
||||
Aaron Seigo \<aseigo@kde.org\><br>
|
||||
Alessandro Diaferia \<alediaferia@gmail.com\><br>
|
||||
Alex Merry \<kde@randomguy3.me.uk\><br>
|
||||
Alexander Wiedenbruch \<wirr01@gmail.com\><br>
|
||||
Alexis Ménard \<darktears31@gmail.com\><br>
|
||||
André Duffeck \<andre@duffeck.de\><br>
|
||||
Andrew Lake \<jamboarder@yahoo.com\><br>
|
||||
Bertjan Broeksema \<b.broeksema@kdemail.net\><br>
|
||||
Chani Armitage \<chanika@gmail.com\><br>
|
||||
Davide Bettio \<davide.bettio@kdemail.net\><br>
|
||||
Dan Meltzer \<hydrogen@notyetimplemented.com\><br>
|
||||
Fredrik Höglund \<fredrik@kde.org\><br>
|
||||
Ivan Cukic \<ivan.cukic+kde@gmail.com\><br>
|
||||
John Tapsell \<tapsell@kde.org\><br>
|
||||
Jordi Polo \<mumismo@gmail.com\><br>
|
||||
Kevin Ottens \<ervin@kde.org\><br>
|
||||
Montel Laurent \<montel@kde.org\<br>
|
||||
Marco Martin \<notmart@gmail.com\><br>
|
||||
Matt Broadstone \<mbroadst@gmail.com\><br>
|
||||
Petri Damsten \<damu@iki.fi\><br>
|
||||
Rafael Fernández López \<ereslibre@kde.org\><br>
|
||||
Riccardo Iaconelli \<riccardo@kde.org\><br>
|
||||
Richard J. Moore \<rich@kde.org\><br>
|
||||
Rob Scheepmaker \<r.scheepmaker@student.utwente.nl\><br>
|
||||
Robert Knight \<robertknight@gmail.com\><br>
|
||||
Sebastian Kuegler \<sebas@kde.org\><br>
|
||||
Siraj Razick \<siraj@kde.net\><br>
|
||||
Zack Rusin \<zack@kde.org\>
|
||||
|
||||
@maintainers
|
||||
Aaron Seigo \<aseigo@kde.org\>
|
||||
|
||||
@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
|
||||
|
47
kdm/CMakeLists.txt
Normal file
47
kdm/CMakeLists.txt
Normal file
@ -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 )
|
4
kdm/Messages.sh
Normal file
4
kdm/Messages.sh
Normal file
@ -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
|
484
kdm/kgreet_classic.cpp
Normal file
484
kdm/kgreet_classic.cpp
Normal file
@ -0,0 +1,484 @@
|
||||
/*
|
||||
|
||||
Conversation widget for kdm greeter
|
||||
|
||||
Copyright (C) 1997, 1998, 2000 Steffen Hansen <hansen@kde.org>
|
||||
Copyright (C) 2000-2003 Oswald Buddenhagen <ossi@kde.org>
|
||||
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "kgreet_classic.h"
|
||||
#include "themer/kdmthemer.h"
|
||||
#include "themer/kdmitem.h"
|
||||
|
||||
#include <kglobal.h>
|
||||
#include <klocale.h>
|
||||
#include <klineedit.h>
|
||||
#include <kuser.h>
|
||||
|
||||
#include <QRegExp>
|
||||
#include <QLayout>
|
||||
#include <QLabel>
|
||||
|
||||
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"
|
84
kdm/kgreet_classic.h
Normal file
84
kdm/kgreet_classic.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
|
||||
Conversation widget for kdm greeter
|
||||
|
||||
Copyright (C) 1997, 1998 Steffen Hansen <hansen@kde.org>
|
||||
Copyright (C) 2000-2003 Oswald Buddenhagen <ossi@kde.org>
|
||||
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef KGREET_CLASSIC_H
|
||||
#define KGREET_CLASSIC_H
|
||||
|
||||
#include "kgreeterplugin.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
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 */
|
354
kdm/kgreet_generic.cpp
Normal file
354
kdm/kgreet_generic.cpp
Normal file
@ -0,0 +1,354 @@
|
||||
/*
|
||||
|
||||
Conversation widget for kdm greeter
|
||||
|
||||
Copyright (C) 2008 Dirk Mueller <mueller@kde.org>
|
||||
Copyright (C) 2008 Oswald Buddenhagen <ossi@kde.org>
|
||||
|
||||
based on classic kdm greeter:
|
||||
|
||||
Copyright (C) 1997, 1998, 2000 Steffen Hansen <hansen@kde.org>
|
||||
Copyright (C) 2000-2003 Oswald Buddenhagen <ossi@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "kgreet_generic.h"
|
||||
|
||||
#include <kglobal.h>
|
||||
#include <klocale.h>
|
||||
#include <klineedit.h>
|
||||
#include <kuser.h>
|
||||
|
||||
#include <QLayout>
|
||||
#include <QLabel>
|
||||
#include <QTextDocument>
|
||||
|
||||
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 = "<qt>";
|
||||
foreach (const QString &msg, m_infoMsgs)
|
||||
text += "<p>" + Qt::escape( msg ) + "</p>";
|
||||
text += "</qt>";
|
||||
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"
|
84
kdm/kgreet_generic.h
Normal file
84
kdm/kgreet_generic.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
|
||||
Conversation widget for kdm greeter
|
||||
|
||||
Copyright (C) 2008 Dirk Mueller <mueller@kde.org>
|
||||
Copyright (C) 2008 Oswald Buddenhagen <ossi@kde.org>
|
||||
|
||||
based on classic kdm greeter:
|
||||
|
||||
Copyright (C) 1997, 1998, 2000 Steffen Hansen <hansen@kde.org>
|
||||
Copyright (C) 2000-2003 Oswald Buddenhagen <ossi@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef KGREET_GENERIC_H
|
||||
#define KGREET_GENERIC_H
|
||||
|
||||
#include "kgreeterplugin.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
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<QWidget *> m_children;
|
||||
KLineEdit *m_lineEdit;
|
||||
QWidget *m_parentWidget;
|
||||
QList<QString> m_infoMsgs;
|
||||
QString fixedUser, curUser;
|
||||
QStringList m_users;
|
||||
Function func;
|
||||
Context ctx;
|
||||
int exp, m_line;
|
||||
bool running, m_echo;
|
||||
};
|
||||
|
||||
#endif /* KGREET_GENERIC_H */
|
627
kdm/kgreet_winbind.cpp
Normal file
627
kdm/kgreet_winbind.cpp
Normal file
@ -0,0 +1,627 @@
|
||||
/*
|
||||
|
||||
Conversation widget for kdm greeter
|
||||
|
||||
Copyright (C) 1997, 1998, 2000 Steffen Hansen <hansen@kde.org>
|
||||
Copyright (C) 2000-2004 Oswald Buddenhagen <ossi@kde.org>
|
||||
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "kgreet_winbind.h"
|
||||
#include "themer/kdmthemer.h"
|
||||
#include "themer/kdmitem.h"
|
||||
|
||||
#include <klocale.h>
|
||||
#include <kglobal.h>
|
||||
#include <kdebug.h>
|
||||
#include <kcombobox.h>
|
||||
#include <klineedit.h>
|
||||
#include <kuser.h>
|
||||
#include <kprocess.h>
|
||||
|
||||
#include <QRegExp>
|
||||
#include <QLayout>
|
||||
#include <QLabel>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QGridLayout>
|
||||
#include <QTextStream>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
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 = "<local>", 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 == "<local>") {
|
||||
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 == "<local>" ? 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 << "<local>";
|
||||
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"
|
94
kdm/kgreet_winbind.h
Normal file
94
kdm/kgreet_winbind.h
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
|
||||
Conversation widget for kdm greeter
|
||||
|
||||
Copyright (C) 1997, 1998 Steffen Hansen <hansen@kde.org>
|
||||
Copyright (C) 2000-2003 Oswald Buddenhagen <ossi@kde.org>
|
||||
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef KGREET_WINBIND_H
|
||||
#define KGREET_WINBIND_H
|
||||
|
||||
#include "kgreeterplugin.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
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 */
|
410
kdm/kgreeterplugin.h
Normal file
410
kdm/kgreeterplugin.h
Normal file
@ -0,0 +1,410 @@
|
||||
/*
|
||||
|
||||
Authentication method specific conversation plugin for KDE's greeter widgets
|
||||
|
||||
Copyright (C) 2003 Oswald Buddenhagen <ossi@kde.org>
|
||||
Copyright (C) 2003 Fabian Kaiser <xfk@softpro.de>
|
||||
|
||||
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 <QtCore/QVariant>
|
||||
#include <QtGui/QMessageBox>
|
||||
#include <kdemacros.h>
|
||||
|
||||
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<QWidget *> 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/<plugin>.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
|
13
ksysguard/CMakeLists.txt
Normal file
13
ksysguard/CMakeLists.txt
Normal file
@ -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 )
|
||||
|
||||
|
8
ksysguard/config-ksysguard.h.cmake
Normal file
8
ksysguard/config-ksysguard.h.cmake
Normal file
@ -0,0 +1,8 @@
|
||||
/* Define to 1 if you have the <sys/ptrace.h> header file. */
|
||||
#cmakedefine HAVE_SYS_PTRACE_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/endian.h> header file. */
|
||||
#cmakedefine HAVE_SYS_ENDIAN_H 1
|
||||
|
||||
/* Define to 1 if you have the <byteswap.h> header file. */
|
||||
#cmakedefine HAVE_BYTESWAP_H 1
|
33
ksysguard/lsofui/CMakeLists.txt
Normal file
33
ksysguard/lsofui/CMakeLists.txt
Normal file
@ -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 )
|
||||
|
46
ksysguard/lsofui/LsofSearchWidget.cpp
Normal file
46
ksysguard/lsofui/LsofSearchWidget.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
KSysGuard, the KDE System Guard
|
||||
|
||||
Copyright (c) 1999 Chris Schlaeger <cs@kde.org>
|
||||
Copyright (c) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 <klocale.h>
|
||||
#include <kdebug.h>
|
||||
|
||||
#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
|
||||
}
|
||||
|
45
ksysguard/lsofui/LsofSearchWidget.h
Normal file
45
ksysguard/lsofui/LsofSearchWidget.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
KSysGuard, the KDE System Guard
|
||||
|
||||
Copyright (c) 2008 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 <kdialog.h>
|
||||
|
||||
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
|
54
ksysguard/lsofui/LsofSearchWidget.ui
Normal file
54
ksysguard/lsofui/LsofSearchWidget.ui
Normal file
@ -0,0 +1,54 @@
|
||||
<ui version="4.0" >
|
||||
<class>KLsofSearchWidget</class>
|
||||
<widget class="QWidget" name="KLsofSearchWidget" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>956</width>
|
||||
<height>686</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" >
|
||||
<item>
|
||||
<widget class="KTreeWidgetSearchLine" name="ktreewidgetsearchline" />
|
||||
</item>
|
||||
<item>
|
||||
<widget class="KLsofWidget" name="klsofwidget" >
|
||||
<property name="rootIsDecorated" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text" >
|
||||
<string>Stream</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text" >
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text" >
|
||||
<string>Filename</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KTreeWidgetSearchLine</class>
|
||||
<extends>KLineEdit</extends>
|
||||
<header>ktreewidgetsearchline.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>KLsofWidget</class>
|
||||
<extends>QTreeWidget</extends>
|
||||
<header>lsof.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
2
ksysguard/lsofui/Messages.sh
Executable file
2
ksysguard/lsofui/Messages.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#! /usr/bin/env bash
|
||||
$XGETTEXT *.cpp -o $podir/ksysguardlsofwidgets.pot
|
8
ksysguard/lsofui/ksysguardlsof.widgets
Normal file
8
ksysguard/lsofui/ksysguardlsof.widgets
Normal file
@ -0,0 +1,8 @@
|
||||
[Global]
|
||||
PluginName=KSysGuardLsofWidgets
|
||||
|
||||
[KLsofWidget]
|
||||
Group=KSysGuard (KDE)
|
||||
ConstructorArgs=(parent)
|
||||
IncludeFile=lsof.h
|
||||
|
86
ksysguard/lsofui/lsof.cpp
Normal file
86
ksysguard/lsofui/lsof.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
#include <QString>
|
||||
#include <QProcess>
|
||||
#include <klocale.h>
|
||||
|
||||
#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"
|
83
ksysguard/lsofui/lsof.h
Normal file
83
ksysguard/lsofui/lsof.h
Normal file
@ -0,0 +1,83 @@
|
||||
/* This file is part of the KDE project
|
||||
|
||||
Copyright (C) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 <QtCore/QObject>
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtGui/QTreeWidget>
|
||||
#include <kapplication.h>
|
||||
|
||||
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
|
28
ksysguard/processcore/CMakeLists.txt
Normal file
28
ksysguard/processcore/CMakeLists.txt
Normal file
@ -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)
|
||||
|
2
ksysguard/processcore/Messages.sh
Executable file
2
ksysguard/processcore/Messages.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#! /usr/bin/env bash
|
||||
$XGETTEXT *.cpp -o $podir/processcore.pot
|
246
ksysguard/processcore/process.cpp
Normal file
246
ksysguard/processcore/process.cpp
Normal file
@ -0,0 +1,246 @@
|
||||
/* This file is part of the KDE project
|
||||
|
||||
Copyright (C) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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;
|
||||
}
|
||||
|
160
ksysguard/processcore/process.h
Normal file
160
ksysguard/processcore/process.h
Normal file
@ -0,0 +1,160 @@
|
||||
/* This file is part of the KDE project
|
||||
|
||||
Copyright (C) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 <kdemacros.h>
|
||||
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QTime>
|
||||
#include <QtCore/QFlags>
|
||||
|
||||
#include <klocale.h>
|
||||
|
||||
|
||||
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<Process *> 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
|
398
ksysguard/processcore/processes.cpp
Normal file
398
ksysguard/processcore/processes.cpp
Normal file
@ -0,0 +1,398 @@
|
||||
/* This file is part of the KDE project
|
||||
|
||||
Copyright (C) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 <klocale.h>
|
||||
#include <kglobal.h>
|
||||
#include <kdebug.h>
|
||||
|
||||
#include <QHash>
|
||||
#include <QSet>
|
||||
#include <QMutableSetIterator>
|
||||
#include <QByteArray>
|
||||
|
||||
//for sysconf
|
||||
#include <unistd.h>
|
||||
|
||||
/* if porting to an OS without signal.h please #define SIGTERM to something */
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
namespace KSysGuard
|
||||
{
|
||||
Processes::StaticPrivate *Processes::d2 = 0;
|
||||
|
||||
class Processes::Private
|
||||
{
|
||||
public:
|
||||
Private() { mAbstractProcesses = 0; mProcesses.insert(0, &mFakeProcess); mElapsedTimeCentiSeconds = -1; ref=1; }
|
||||
~Private();
|
||||
|
||||
QSet<long> mToBeProcessed;
|
||||
QSet<long> mProcessedLastTime;
|
||||
|
||||
QHash<long, Process *> mProcesses; //This must include mFakeProcess at pid 0
|
||||
QList<Process *> 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<QString, Processes*> 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<Process *> 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<long> beingProcessed(d->mToBeProcessed); //keep a copy so that we can replace mProcessedLastTime with this at the end of this function
|
||||
|
||||
long pid;
|
||||
{
|
||||
QMutableSetIterator<long> 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<long> 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<QByteArray>& answer ) {
|
||||
KSysGuard::ProcessesRemote *processes = dynamic_cast<KSysGuard::ProcessesRemote *>(d->mAbstractProcesses);
|
||||
if(processes)
|
||||
processes->answerReceived(id, answer);
|
||||
}
|
||||
|
||||
}
|
||||
#include "processes.moc"
|
||||
|
224
ksysguard/processcore/processes.h
Normal file
224
ksysguard/processcore/processes.h
Normal file
@ -0,0 +1,224 @@
|
||||
/* This file is part of the KDE project
|
||||
|
||||
Copyright (C) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 <kdemacros.h>
|
||||
|
||||
#include "process.h"
|
||||
#include <QtCore/QHash>
|
||||
|
||||
namespace KSysGuard
|
||||
{
|
||||
class AbstractProcesses;
|
||||
/**
|
||||
* This class retrieves the processes currently running in an OS independent way.
|
||||
*
|
||||
* To use, do something like:
|
||||
*
|
||||
* \code
|
||||
* #include <ksysguard/processes.h>
|
||||
* #include <ksysguard/process.h>
|
||||
*
|
||||
* KSysGuard::Processes *processes = KSysGuard::Processes::getInstance();
|
||||
* QHash<long, Process *> 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 <tapsell@kde.org>
|
||||
*/
|
||||
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 <signals.h>
|
||||
* ...
|
||||
*
|
||||
* 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<QByteArray>& answer );
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
22
ksysguard/processcore/processes_base_p.cpp
Normal file
22
ksysguard/processcore/processes_base_p.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
/* This file is part of the KDE project
|
||||
|
||||
Copyright (C) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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"
|
139
ksysguard/processcore/processes_base_p.h
Normal file
139
ksysguard/processcore/processes_base_p.h
Normal file
@ -0,0 +1,139 @@
|
||||
/* This file is part of the KDE project
|
||||
|
||||
Copyright (C) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 <QSet>
|
||||
#include <QObject>
|
||||
|
||||
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 <tapsell@kde.org>
|
||||
*/
|
||||
class AbstractProcesses : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
AbstractProcesses() {}
|
||||
virtual ~AbstractProcesses() {}
|
||||
/**
|
||||
* To get information about processes, this will be the first function called.
|
||||
*/
|
||||
virtual QSet<long> 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 <signals.h>
|
||||
* ...
|
||||
*
|
||||
* 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
|
307
ksysguard/processcore/processes_freebsd_p.cpp
Normal file
307
ksysguard/processcore/processes_freebsd_p.cpp
Normal file
@ -0,0 +1,307 @@
|
||||
/* This file is part of the KDE project
|
||||
Copyright (C) 2007 Manolo Valdes <nolis71cu@gmail.com>
|
||||
|
||||
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 <klocale.h>
|
||||
|
||||
#include <QSet>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/resource.h>
|
||||
#if defined(__DragonFly__)
|
||||
#include <sys/resourcevar.h>
|
||||
#include <err.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sched.h>
|
||||
|
||||
|
||||
|
||||
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<long> ProcessesLocal::getAllPids( )
|
||||
{
|
||||
QSet<long> 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;
|
||||
}
|
||||
|
||||
}
|
517
ksysguard/processcore/processes_linux_p.cpp
Normal file
517
ksysguard/processcore/processes_linux_p.cpp
Normal file
@ -0,0 +1,517 @@
|
||||
/* This file is part of the KDE project
|
||||
|
||||
Copyright (C) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 <klocale.h>
|
||||
|
||||
#include <QFile>
|
||||
#include <QHash>
|
||||
#include <QSet>
|
||||
#include <QByteArray>
|
||||
#include <QTextStream>
|
||||
|
||||
//for sysconf
|
||||
#include <unistd.h>
|
||||
//for kill and setNice
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <sys/resource.h>
|
||||
#include <dirent.h>
|
||||
#include <stdlib.h>
|
||||
//for ionice
|
||||
#include <sys/ptrace.h>
|
||||
#include <asm/unistd.h>
|
||||
//for getsched
|
||||
#include <sched.h>
|
||||
|
||||
#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<long> ProcessesLocal::getAllPids( )
|
||||
{
|
||||
QSet<long> 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;
|
||||
}
|
||||
|
||||
}
|
37
ksysguard/processcore/processes_local_p.cpp
Normal file
37
ksysguard/processcore/processes_local_p.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
/* This file is part of the KDE project
|
||||
|
||||
Copyright (C) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 <qglobal.h>
|
||||
#ifdef Q_OS_SOLARIS
|
||||
#include "processes_solaris_p.cpp"
|
||||
#endif
|
||||
#endif
|
||||
|
70
ksysguard/processcore/processes_local_p.h
Normal file
70
ksysguard/processcore/processes_local_p.h
Normal file
@ -0,0 +1,70 @@
|
||||
/* This file is part of the KDE project
|
||||
|
||||
Copyright (C) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 <unistd.h> //For sysconf
|
||||
|
||||
|
||||
#include <QSet>
|
||||
|
||||
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<long> 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
|
292
ksysguard/processcore/processes_netbsd_p.cpp
Normal file
292
ksysguard/processcore/processes_netbsd_p.cpp
Normal file
@ -0,0 +1,292 @@
|
||||
/* This file is part of the KDE project
|
||||
Copyright (C) 2007 Manolo Valdes <nolis71cu@gmail.com>
|
||||
Copyright (C) 2007 Mark Davies <mark@mcs.vuw.ac.nz>
|
||||
|
||||
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 <klocale.h>
|
||||
|
||||
#include <QSet>
|
||||
|
||||
#include <kvm.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sched.h>
|
||||
|
||||
|
||||
|
||||
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<long> ProcessesLocal::getAllPids( )
|
||||
{
|
||||
QSet<long> 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;
|
||||
}
|
||||
|
||||
}
|
306
ksysguard/processcore/processes_openbsd_p.cpp
Normal file
306
ksysguard/processcore/processes_openbsd_p.cpp
Normal file
@ -0,0 +1,306 @@
|
||||
/* This file is part of the KDE project
|
||||
Copyright (C) 2007 Manolo Valdes <nolis71cu@gmail.com>
|
||||
|
||||
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 <klocale.h>
|
||||
|
||||
#include <QSet>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/resource.h>
|
||||
#if defined(__DragonFly__)
|
||||
#include <sys/resourcevar.h>
|
||||
#include <err.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
|
||||
|
||||
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<long> ProcessesLocal::getAllPids( )
|
||||
{
|
||||
QSet<long> 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;
|
||||
}
|
||||
|
||||
}
|
267
ksysguard/processcore/processes_remote_p.cpp
Normal file
267
ksysguard/processcore/processes_remote_p.cpp
Normal file
@ -0,0 +1,267 @@
|
||||
/* This file is part of the KDE project
|
||||
|
||||
Copyright (C) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 <QString>
|
||||
#include <QSet>
|
||||
#include <QTimer>
|
||||
|
||||
#include <klocale.h>
|
||||
#include <kdebug.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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<QByteArray> lastAnswer;
|
||||
QSet<long> pids;
|
||||
QHash<long, QList<QByteArray> > 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<QByteArray> 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<long> ProcessesRemote::getAllPids( )
|
||||
{
|
||||
d->pids.clear();
|
||||
d->processByPid.clear();
|
||||
foreach(const QByteArray &process, d->lastAnswer) {
|
||||
QList<QByteArray> 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<QByteArray>& answer ) {
|
||||
switch (id) {
|
||||
case PsInfo: {
|
||||
if(answer.isEmpty()) return; //Invalid data
|
||||
QList<QByteArray> 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"
|
||||
|
78
ksysguard/processcore/processes_remote_p.h
Normal file
78
ksysguard/processcore/processes_remote_p.h
Normal file
@ -0,0 +1,78 @@
|
||||
/* This file is part of the KDE project
|
||||
|
||||
Copyright (C) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 <QSet>
|
||||
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<long> 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<QByteArray>& 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
|
100
ksysguard/processcore/processes_solaris_p.cpp
Normal file
100
ksysguard/processcore/processes_solaris_p.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
/* This file is part of the KDE project
|
||||
Copyright (C) 2007 Adriaan de Groot <groot@kde.org>
|
||||
|
||||
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 <klocale.h>
|
||||
|
||||
#include <QSet>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/resource.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sched.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#warning Totally bogus ProcessesLocal implementation
|
||||
#endif
|
||||
|
||||
namespace KSysGuard
|
||||
{
|
||||
|
||||
class ProcessesLocal::Private
|
||||
{
|
||||
public:
|
||||
Private() { };
|
||||
~Private() { };
|
||||
} ;
|
||||
|
||||
ProcessesLocal::ProcessesLocal() : d(0)
|
||||
{
|
||||
}
|
||||
|
||||
long ProcessesLocal::getParentPid(long pid) {
|
||||
long long ppid = 0;
|
||||
return ppid;
|
||||
}
|
||||
|
||||
bool ProcessesLocal::updateProcessInfo( long pid, Process *process)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QSet<long> ProcessesLocal::getAllPids( )
|
||||
{
|
||||
QSet<long> pids;
|
||||
return pids;
|
||||
}
|
||||
|
||||
bool ProcessesLocal::sendSignal(long pid, int sig) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProcessesLocal::setNiceness(long pid, int priority) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProcessesLocal::setScheduler(long pid, int priorityClass, int priority)
|
||||
{
|
||||
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() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ProcessesLocal::~ProcessesLocal()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
}
|
91
ksysguard/processui/CMakeLists.txt
Normal file
91
ksysguard/processui/CMakeLists.txt
Normal file
@ -0,0 +1,91 @@
|
||||
|
||||
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../ ../processcore/)
|
||||
|
||||
check_include_files(sys/ptrace.h HAVE_SYS_PTRACE_H)
|
||||
check_include_files(sys/endian.h HAVE_SYS_ENDIAN_H)
|
||||
check_include_files(byteswap.h HAVE_BYTESWAP_H)
|
||||
|
||||
if (HAVE_SYS_PTRACE_H)
|
||||
set(_SUPPORTED_REGS_STRUCT_CHECK "
|
||||
#include <sys/user.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#if defined(__i386__)
|
||||
# define _regs_struct user_regs_struct
|
||||
# define REG_ORIG_ACCUM orig_eax
|
||||
#elif defined( __amd64__)
|
||||
# define _regs_struct user_regs_struct
|
||||
# define REG_ORIG_ACCUM orig_rax
|
||||
#elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__) || defined(__PPC__) || defined(powerpc)
|
||||
# define _regs_struct pt_regs;
|
||||
# define REG_ORIG_ACCUM gpr[0]
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
struct _regs_struct* regs;
|
||||
return regs->REG_ORIG_ACCUM == SYS_fork;
|
||||
}")
|
||||
|
||||
include(CheckCSourceCompiles)
|
||||
check_c_source_compiles("${_SUPPORTED_REGS_STRUCT_CHECK}" HAVE_KSYSGUARD_SUPPORTED_REGS_STRUCT)
|
||||
else (HAVE_SYS_PTRACE_H)
|
||||
# Even if we don't have ptrace, we need KMonitorProcessIO.cpp
|
||||
# because the widget is referenced from the .widgets file and
|
||||
# from the .ui files.
|
||||
set(HAVE_KSYSGUARD_SUPPORTED_REGS_STRUCT "NO")
|
||||
endif (HAVE_SYS_PTRACE_H)
|
||||
|
||||
if (HAVE_KSYSGUARD_SUPPORTED_REGS_STRUCT)
|
||||
add_definitions(-DWITH_MONITOR_PROCESS_IO)
|
||||
set(processui_ptrace_SRCS KMonitorProcessIO.cpp DisplayProcessDlg.cpp)
|
||||
set(ksysguard_WIDGETS "${CMAKE_CURRENT_BINARY_DIR}/ksysguard.generated_widgets")
|
||||
|
||||
# Merge both widget files
|
||||
file(READ ksysguard.widgets _ksysguard_buffer)
|
||||
file(WRITE ${ksysguard_WIDGETS} "${_ksysguard_buffer}")
|
||||
file(READ KMonitorProcessIO.widgets _ksysguard_buffer)
|
||||
file(APPEND ${ksysguard_WIDGETS} "${_ksysguard_buffer}")
|
||||
else (HAVE_KSYSGUARD_SUPPORTED_REGS_STRUCT)
|
||||
set(processui_ptrace_SRCS )
|
||||
set(ksysguard_WIDGETS "ksysguard.widgets")
|
||||
endif (HAVE_KSYSGUARD_SUPPORTED_REGS_STRUCT)
|
||||
|
||||
set(processui_LIB_SRCS
|
||||
ksysguardprocesslist.cpp
|
||||
ProcessFilter.cc
|
||||
ProcessModel.cc
|
||||
ReniceDlg.cc
|
||||
KTextEditVT.cpp
|
||||
${processui_ptrace_SRCS}
|
||||
)
|
||||
|
||||
kde4_add_ui_files( processui_LIB_SRCS
|
||||
ReniceDlgUi.ui
|
||||
ProcessWidgetUI.ui
|
||||
DisplayProcessUi.ui
|
||||
)
|
||||
|
||||
|
||||
kde4_add_library(processui SHARED ${processui_LIB_SRCS})
|
||||
|
||||
target_link_libraries(processui ${KDE4_KDEUI_LIBS} processcore)
|
||||
|
||||
set_target_properties(processui
|
||||
PROPERTIES VERSION ${GENERIC_LIB_VERSION}
|
||||
SOVERSION ${GENERIC_LIB_SOVERSION}
|
||||
${KDE4_DISABLE_PROPERTY_}LINK_INTERFACE_LIBRARIES "${KDE4_KDEUI_LIBS};processcore"
|
||||
)
|
||||
|
||||
install(TARGETS processui ${INSTALL_TARGETS_DEFAULT_ARGS} )
|
||||
|
||||
#----------------------
|
||||
|
||||
KDE4_ADD_WIDGET_FILES(ksysguardwidgets_PART_SRCS ${ksysguard_WIDGETS})
|
||||
|
||||
kde4_add_plugin(ksysguardwidgets ${ksysguardwidgets_PART_SRCS})
|
||||
|
||||
target_link_libraries(ksysguardwidgets ${KDE4_KDEUI_LIBS} processui)
|
||||
|
||||
install(TARGETS ksysguardwidgets DESTINATION ${PLUGIN_INSTALL_DIR}/plugins/designer )
|
||||
|
||||
install( FILES ProcessModel.h DisplayProcessDlg.h ProcessFilter.h KTextEditVT.h ksysguardprocesslist.h DESTINATION ${INCLUDE_INSTALL_DIR}/ksysguard COMPONENT Devel)
|
100
ksysguard/processui/DisplayProcessDlg.cpp
Normal file
100
ksysguard/processui/DisplayProcessDlg.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
KSysGuard, the KDE System Guard
|
||||
|
||||
Copyright (C) 2007 Trent Waddington <trent.waddington@gmail.com>
|
||||
Copyright (c) 2008 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 "KMonitorProcessIO.h"
|
||||
#include "DisplayProcessDlg.h"
|
||||
#include "DisplayProcessDlg.moc"
|
||||
#include "ui_DisplayProcessUi.h"
|
||||
|
||||
DisplayProcessDlg::DisplayProcessDlg(QWidget* parent, KSysGuard::Process *process)
|
||||
: KDialog( parent )
|
||||
{
|
||||
setObjectName( "Display Process Dialog" );
|
||||
setModal( false );
|
||||
setCaption( i18n("Monitoring I/O for %1 (%2)", process->pid, process->name) );
|
||||
setButtons( Close );
|
||||
//enableLinkedHelp( true );
|
||||
showButtonSeparator( true );
|
||||
|
||||
QWidget *widget = new QWidget(this);
|
||||
setMainWidget(widget);
|
||||
ui = new Ui_DisplayProcessUi();
|
||||
ui->setupUi(widget);
|
||||
|
||||
ui->mTextEdit->setWhatsThis(i18n("The program '%1' (PID: %2) is being monitored for input and output through any file descriptor (stdin, stdout, stderr, open files, network connections, etc.). Data being written by the process is shown in red and data being read by the process is shown in blue.", process->name, process->pid));
|
||||
if(!ui->mTextEdit->attach(process->pid)) {
|
||||
ui->btnDetach->setText(i18n("&Attach"));
|
||||
ui->btnDetach->setChecked(true);
|
||||
ui->btnPause->setText(i18n("&Pause"));
|
||||
ui->btnPause->setChecked(false);
|
||||
ui->btnPause->setEnabled(false);
|
||||
|
||||
}
|
||||
connect(ui->btnPause, SIGNAL(toggled(bool)), this, SLOT(slotBtnPause(bool)));
|
||||
connect(ui->btnDetach, SIGNAL(toggled(bool)), this, SLOT(slotBtnDetach(bool)));
|
||||
}
|
||||
|
||||
DisplayProcessDlg::~DisplayProcessDlg() {
|
||||
ui->mTextEdit->detach();
|
||||
}
|
||||
void DisplayProcessDlg::slotButtonClicked(int)
|
||||
{
|
||||
ui->mTextEdit->detach();
|
||||
accept();
|
||||
}
|
||||
|
||||
QSize DisplayProcessDlg::sizeHint() const {
|
||||
return QSize(600,600);
|
||||
}
|
||||
|
||||
void DisplayProcessDlg::slotBtnPause(bool pause) {
|
||||
if(pause) {
|
||||
ui->mTextEdit->pauseProcesses();
|
||||
ui->btnPause->setText(i18n("&Resume"));
|
||||
} else {
|
||||
ui->mTextEdit->resumeProcesses();
|
||||
ui->btnPause->setText(i18n("&Pause"));
|
||||
}
|
||||
}
|
||||
void DisplayProcessDlg::slotBtnDetach(bool detach) {
|
||||
if(detach) {
|
||||
ui->btnDetach->setText(i18n("&Attach"));
|
||||
ui->btnDetach->setChecked(true);
|
||||
ui->btnPause->setText(i18n("&Pause"));
|
||||
ui->btnPause->setChecked(false);
|
||||
ui->btnPause->setEnabled(false);
|
||||
ui->mTextEdit->detach();
|
||||
} else {
|
||||
if(!ui->mTextEdit->reattach()) {
|
||||
//failed to attached
|
||||
ui->btnDetach->setText(i18n("&Attach"));
|
||||
ui->btnDetach->setChecked(true);
|
||||
ui->btnPause->setText(i18n("&Pause"));
|
||||
ui->btnPause->setChecked(false);
|
||||
ui->btnPause->setEnabled(false);
|
||||
} else
|
||||
ui->btnDetach->setText(i18n("&Detach"));
|
||||
}
|
||||
}
|
||||
|
53
ksysguard/processui/DisplayProcessDlg.h
Normal file
53
ksysguard/processui/DisplayProcessDlg.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
KSysGuard, the KDE System Guard
|
||||
|
||||
Copyright (c) 2008 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 _DisplayProcessDlg_h_
|
||||
#define _DisplayProcessDlg_h_
|
||||
|
||||
#include <kdialog.h>
|
||||
#include <kprocess.h>
|
||||
#include "processes.h"
|
||||
|
||||
class Ui_DisplayProcessUi;
|
||||
|
||||
class DisplayProcessDlg : public KDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DisplayProcessDlg(QWidget* parent, KSysGuard::Process *process);
|
||||
~DisplayProcessDlg();
|
||||
/** Returns the default size of the dialog. Reimplmentation from QDialog */
|
||||
virtual QSize sizeHint() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
/** Close button has been clicked. Reimplementation from KDialog */
|
||||
virtual void slotButtonClicked(int);
|
||||
void slotBtnPause(bool pause);
|
||||
void slotBtnDetach(bool detach);
|
||||
|
||||
private:
|
||||
Ui_DisplayProcessUi *ui;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
170
ksysguard/processui/DisplayProcessUi.ui
Normal file
170
ksysguard/processui/DisplayProcessUi.ui
Normal file
@ -0,0 +1,170 @@
|
||||
<ui version="4.0" >
|
||||
<class>DisplayProcessUi</class>
|
||||
<widget class="QWidget" name="DisplayProcessUi" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>681</width>
|
||||
<height>863</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" >
|
||||
<property name="spacing" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="KMonitorProcessIO" name="mTextEdit" />
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkColorOutput" >
|
||||
<property name="toolTip" >
|
||||
<string>Interpret output as containing VT100 commands. For console-based programs.</string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string>If this is checked then ANSI escape sequences will be interpreted and not displayed. Useful for when monitoring bash.</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Interpret ANSI escape sequences</string>
|
||||
</property>
|
||||
<property name="checked" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkMonitorChildProcesses" >
|
||||
<property name="statusTip" >
|
||||
<string>Show the output from processes launched by this process.</string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string>Follow fork and clone commands to monitor child processes</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Monitor child processes</string>
|
||||
</property>
|
||||
<property name="checked" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" >
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnPause" >
|
||||
<property name="toolTip" >
|
||||
<string>Pause the process and its output</string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string>Stop reading the output from the process. This will cause the process to be blocked, effectively pausing it. The process can be resumed by resuming, detaching or closing the dialog.</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>&Pause</string>
|
||||
</property>
|
||||
<property name="checkable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer" >
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0" >
|
||||
<size>
|
||||
<width>58</width>
|
||||
<height>27</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnDetach" >
|
||||
<property name="statusTip" >
|
||||
<string>Stop monitoring the process</string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string>Stop monitoring the process and allow the process to resume running.</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>&Detach</string>
|
||||
</property>
|
||||
<property name="checkable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KMonitorProcessIO</class>
|
||||
<extends>KTextEditVT</extends>
|
||||
<header>KMonitorProcessIO.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>mTextEdit</tabstop>
|
||||
<tabstop>chkColorOutput</tabstop>
|
||||
<tabstop>chkMonitorChildProcesses</tabstop>
|
||||
<tabstop>btnPause</tabstop>
|
||||
<tabstop>btnDetach</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>chkColorOutput</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>mTextEdit</receiver>
|
||||
<slot>setParseAnsiEscapeCodes(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>55</x>
|
||||
<y>795</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>51</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>chkMonitorChildProcesses</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>mTextEdit</receiver>
|
||||
<slot>setIncludeChildProcesses(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>281</x>
|
||||
<y>822</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>277</x>
|
||||
<y>258</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>btnDetach</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>btnPause</receiver>
|
||||
<slot>setDisabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>624</x>
|
||||
<y>847</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>75</x>
|
||||
<y>837</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
330
ksysguard/processui/KMonitorProcessIO.cpp
Normal file
330
ksysguard/processui/KMonitorProcessIO.cpp
Normal file
@ -0,0 +1,330 @@
|
||||
/*
|
||||
KSysGuard, the KDE System Guard
|
||||
|
||||
Copyright (C) 2007 Trent Waddington <trent.waddington@gmail.com>
|
||||
Copyright (c) 2008 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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
|
||||
aint 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 "../config-ksysguard.h"
|
||||
|
||||
#include <klocale.h>
|
||||
#include <kdebug.h>
|
||||
#include <QTimer>
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_SYS_PTRACE_H
|
||||
#include <sys/ptrace.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/user.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef __i386__
|
||||
#define REG_ORIG_ACCUM(regs) regs.orig_eax
|
||||
#define REG_ACCUM(regs) regs.eax
|
||||
#define REG_PARAM1(regs) regs.ebx
|
||||
#define REG_PARAM2(regs) regs.ecx
|
||||
#define REG_PARAM3(regs) regs.edx
|
||||
#endif
|
||||
#ifdef __amd64__
|
||||
#define REG_ORIG_ACCUM(regs) regs.orig_rax
|
||||
#define REG_ACCUM(regs) regs.rax
|
||||
#define REG_PARAM1(regs) regs.rdi
|
||||
#define REG_PARAM2(regs) regs.rsi
|
||||
#define REG_PARAM3(regs) regs.rdx
|
||||
#endif
|
||||
#if defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__) || defined(__PPC__) || defined(powerpc)
|
||||
#define REG_ORIG_ACCUM(regs) regs.gpr[0]
|
||||
#define REG_ACCUM(regs) regs.gpr[3]
|
||||
#define REG_PARAM1(regs) regs.orig_gpr3
|
||||
#define REG_PARAM2(regs) regs.gpr[4]
|
||||
#define REG_PARAM3(regs) regs.gpr[5]
|
||||
#ifndef PT_ORIG_R3
|
||||
#define PT_ORIG_R3 34
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __ia64__
|
||||
#undef slots
|
||||
#include <sys/rse.h>
|
||||
#define REG_ORIG_ACCUM(regs) regs.pt.gr[15]
|
||||
#define REG_ACCUM(regs) (regs.pt.gr[10] ? -regs.pt.gr[8] : regs.pt.gr[8])
|
||||
#define REG_PARAM1(regs) regs.arg[0]
|
||||
#define REG_PARAM2(regs) regs.arg[1]
|
||||
#define REG_PARAM3(regs) regs.arg[2]
|
||||
#endif
|
||||
|
||||
#include "KMonitorProcessIO.h"
|
||||
|
||||
#include "KMonitorProcessIO.moc"
|
||||
|
||||
KMonitorProcessIO::KMonitorProcessIO(QWidget* parent, int pid)
|
||||
: KTextEditVT( parent ), mPid(pid)
|
||||
{
|
||||
mIncludeChildProcesses = true;
|
||||
remove_duplicates = false;
|
||||
|
||||
mUpdateInterval = 20;
|
||||
mTimer.setSingleShot(false);
|
||||
connect(&mTimer, SIGNAL(timeout()), this, SLOT(update()));
|
||||
|
||||
lastdir = 3; //an invalid direction, so that the color gets set the first time
|
||||
|
||||
setReadOnly(true);
|
||||
setParseAnsiEscapeCodes(true);
|
||||
document()->setMaximumBlockCount(100);
|
||||
mCursor = textCursor();
|
||||
|
||||
|
||||
if(pid == -1)
|
||||
return;
|
||||
attach(mPid);
|
||||
}
|
||||
|
||||
KMonitorProcessIO::~KMonitorProcessIO() {
|
||||
detach();
|
||||
}
|
||||
|
||||
int KMonitorProcessIO::updateInterval() const {
|
||||
return mUpdateInterval;
|
||||
}
|
||||
|
||||
void KMonitorProcessIO::setUpdateInterval(int msecs) {
|
||||
mUpdateInterval = msecs;
|
||||
if(mTimer.isActive()) {
|
||||
mTimer.stop();
|
||||
mTimer.start(msecs); //Start with the new interval time
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void KMonitorProcessIO::detach() {
|
||||
foreach(int pid, attached_pids) {
|
||||
detach(pid);
|
||||
}
|
||||
}
|
||||
|
||||
int KMonitorProcessIO::attachedPid() const {
|
||||
return mPid;
|
||||
}
|
||||
void KMonitorProcessIO::detach(int pid) {
|
||||
int status;
|
||||
#ifdef HAVE_SYS_PTRACE_H
|
||||
if(!ptrace(PTRACE_DETACH, pid, 0, 0)) {
|
||||
//successfully detached
|
||||
} else if(kill(pid, 0) < 0) {
|
||||
if(errno != ESRCH)
|
||||
kDebug() << "Something seriously strange when trying to detach.";
|
||||
} else if (kill(pid, SIGSTOP) < 0) {
|
||||
if (errno != ESRCH)
|
||||
kDebug() << "Something seriously strange when trying to detach and then trying to stop the process";
|
||||
} else {
|
||||
for (;;) {
|
||||
if (waitpid(pid, &status, 0) < 0) {
|
||||
if (errno != ECHILD)
|
||||
kDebug() << "Something seriously strange when trying to detach and waiting for process to stop";
|
||||
break;
|
||||
}
|
||||
if (!WIFSTOPPED(status)) {
|
||||
/* Au revoir, mon ami. */
|
||||
break;
|
||||
}
|
||||
if (WSTOPSIG(status) == SIGSTOP) {
|
||||
//Okay process is now stopped. Lets try detaching again. Silly linux.
|
||||
if (ptrace(PTRACE_DETACH,pid, 0, 0) < 0) {
|
||||
if (errno != ESRCH)
|
||||
kDebug() << "Something seriously strange when trying to detach the second time.";
|
||||
/* I died trying. */
|
||||
}
|
||||
break;
|
||||
}
|
||||
// we didn't manage to stop the process. Lets try continuing it and the stopping it
|
||||
if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) {
|
||||
if (errno != ESRCH)
|
||||
kDebug() << "Something seriously strange when trying to detach and continue";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
attached_pids.removeAll(pid);
|
||||
|
||||
if(attached_pids.isEmpty()) {
|
||||
mTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
bool KMonitorProcessIO::reattach() {
|
||||
if(mPid == -1)
|
||||
return false;
|
||||
return attach(mPid);
|
||||
}
|
||||
|
||||
bool KMonitorProcessIO::attach(int pid) {
|
||||
if(pid == -1) {
|
||||
//Indicates to detach all
|
||||
detach();
|
||||
return false;
|
||||
}
|
||||
#ifdef HAVE_SYS_PTRACE_H
|
||||
if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
|
||||
kDebug() << "Failed to attach to process " << pid;
|
||||
if(attached_pids.isEmpty()) {
|
||||
mTimer.stop();
|
||||
insertHtml(i18n("<br/><i><font color=\"gray\">Failed to attach to process %1</font></i><br/>", pid));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if(attached_pids.isEmpty()) {
|
||||
//First process added. Automatically start timer
|
||||
ptrace(PTRACE_SYSCALL, pid, 0, 0);
|
||||
mTimer.start(mUpdateInterval);
|
||||
if(mPid == -1)
|
||||
mPid = pid;
|
||||
}
|
||||
attached_pids.append(pid);
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void KMonitorProcessIO::update(bool modified)
|
||||
{
|
||||
#ifdef HAVE_SYS_PTRACE_H
|
||||
static QColor writeColor = QColor(255,0,0);
|
||||
static QColor readColor = QColor(0,0,255);
|
||||
|
||||
int status;
|
||||
int pid = waitpid(-1, &status, WNOHANG | WUNTRACED | WCONTINUED);
|
||||
if (pid == -1 || !WIFSTOPPED(status)) {
|
||||
if(modified)
|
||||
ensureCursorVisible();
|
||||
return;
|
||||
}
|
||||
#if defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__) || defined(__PPC__) || defined(powerpc)
|
||||
struct pt_regs regs;
|
||||
regs.gpr[0] = ptrace(PTRACE_PEEKUSER, pid, 4 * PT_R0, 0);
|
||||
regs.gpr[3] = ptrace(PTRACE_PEEKUSER, pid, 4 * PT_R3, 0);
|
||||
regs.gpr[4] = ptrace(PTRACE_PEEKUSER, pid, 4 * PT_R4, 0);
|
||||
regs.gpr[5] = ptrace(PTRACE_PEEKUSER, pid, 4 * PT_R5, 0);
|
||||
regs.orig_gpr3 = ptrace(PTRACE_PEEKUSER, pid, 4 * PT_ORIG_R3, 0);
|
||||
#endif
|
||||
#ifdef __ia64__
|
||||
struct {
|
||||
struct pt_all_user_regs pt;
|
||||
unsigned long arg[3];
|
||||
} regs;
|
||||
ptrace(PTRACE_GETREGS, pid, 0, ®s.pt);
|
||||
if (REG_ORIG_ACCUM(regs) >= 0) {
|
||||
unsigned long *out0 = ia64_rse_skip_regs((unsigned long *)regs.pt.ar[17], -(regs.pt.cfm & 0x7f) + ((regs.pt.cfm >> 7) & 0x7f));
|
||||
regs.arg[0] = ptrace(PTRACE_PEEKDATA, pid, ia64_rse_skip_regs(out0, 0), 0);
|
||||
regs.arg[1] = ptrace(PTRACE_PEEKDATA, pid, ia64_rse_skip_regs(out0, 1), 0);
|
||||
regs.arg[2] = ptrace(PTRACE_PEEKDATA, pid, ia64_rse_skip_regs(out0, 2), 0);
|
||||
}
|
||||
#endif
|
||||
#if defined __i386__ || defined __amd64__
|
||||
struct user_regs_struct regs;
|
||||
ptrace(PTRACE_GETREGS, pid, 0, ®s);
|
||||
#endif
|
||||
/*unsigned int b = ptrace(PTRACE_PEEKTEXT, pid, regs.eip, 0);*/
|
||||
if (mIncludeChildProcesses && (
|
||||
#ifdef SYS_fork
|
||||
REG_ORIG_ACCUM(regs) == SYS_fork ||
|
||||
#endif
|
||||
#ifdef SYS_clone
|
||||
REG_ORIG_ACCUM(regs) == SYS_clone ||
|
||||
#endif
|
||||
#ifdef SYS_clone2
|
||||
REG_ORIG_ACCUM(regs) == SYS_clone2 ||
|
||||
#endif
|
||||
0)) {
|
||||
if (REG_ACCUM(regs) > 0)
|
||||
attach(REG_ACCUM(regs));
|
||||
}
|
||||
if ((REG_ORIG_ACCUM(regs) == SYS_read || REG_ORIG_ACCUM(regs) == SYS_write) && (REG_PARAM3(regs) == REG_ACCUM(regs))) {
|
||||
for (unsigned long i = 0; i < REG_PARAM3(regs); i++) {
|
||||
union {
|
||||
unsigned long l;
|
||||
unsigned char c[sizeof(long)];
|
||||
} a;
|
||||
a.l = ptrace(PTRACE_PEEKDATA, pid, REG_PARAM2(regs) + i, 0);
|
||||
if(!modified) {
|
||||
//Before we add text or change the color, make sure we are at the end
|
||||
moveCursor(QTextCursor::End);
|
||||
}
|
||||
if(REG_ORIG_ACCUM(regs) != lastdir) {
|
||||
if(REG_ORIG_ACCUM(regs) == SYS_read)
|
||||
setTextColor(readColor);
|
||||
else
|
||||
setTextColor(writeColor);
|
||||
lastdir = REG_ORIG_ACCUM(regs);
|
||||
}
|
||||
for (unsigned j = 0; j < sizeof(a.c) && i < REG_PARAM3(regs); i++, j++) {
|
||||
unsigned char c = a.c[j];
|
||||
/** Use the KTextEditVT specific function to parse the character 'c' */
|
||||
insertVTChar(QChar(c));
|
||||
}
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
ptrace(PTRACE_SYSCALL, pid, 0, 0);
|
||||
update(modified);
|
||||
#endif
|
||||
}
|
||||
|
||||
void KMonitorProcessIO::setIncludeChildProcesses(bool include) {
|
||||
mIncludeChildProcesses = include;
|
||||
}
|
||||
|
||||
bool KMonitorProcessIO::includeChildProcesses() const {
|
||||
return mIncludeChildProcesses;
|
||||
}
|
||||
|
||||
|
||||
KMonitorProcessIO::State KMonitorProcessIO::state() const {
|
||||
if(attached_pids.isEmpty())
|
||||
return Detached;
|
||||
if(mTimer.isActive())
|
||||
return AttachedRunning;
|
||||
return AttachedPaused;
|
||||
}
|
||||
|
||||
void KMonitorProcessIO::pauseProcesses() {
|
||||
if(state() == AttachedRunning) {
|
||||
mTimer.stop();
|
||||
}
|
||||
}
|
||||
void KMonitorProcessIO::resumeProcesses() {
|
||||
if(state() == AttachedPaused)
|
||||
mTimer.start(mUpdateInterval);
|
||||
}
|
||||
|
||||
void KMonitorProcessIO::setState(State new_state) {
|
||||
if(new_state == AttachedPaused) pauseProcesses();
|
||||
if(new_state == AttachedRunning) resumeProcesses();
|
||||
if(new_state == Detached) detach();
|
||||
}
|
||||
|
||||
|
115
ksysguard/processui/KMonitorProcessIO.h
Normal file
115
ksysguard/processui/KMonitorProcessIO.h
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
KSysGuard, the KDE System Guard
|
||||
|
||||
Copyright (c) 2008 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 _KMonitorProcessIO_h_
|
||||
#define _KMonitorProcessIO_h_
|
||||
|
||||
#include <QtCore/QTimer>
|
||||
#include "KTextEditVT.h"
|
||||
#include <kdialog.h>
|
||||
#include <kprocess.h>
|
||||
#include "processes.h"
|
||||
|
||||
class KDE_EXPORT KMonitorProcessIO : public KTextEditVT
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( bool includeChildProcesses READ includeChildProcesses WRITE setIncludeChildProcesses )
|
||||
Q_PROPERTY( bool updateInterval READ updateInterval WRITE setUpdateInterval )
|
||||
Q_PROPERTY( int attachedPid READ attachedPid WRITE attach )
|
||||
Q_PROPERTY( State status READ state WRITE setState )
|
||||
Q_ENUMS( State )
|
||||
|
||||
public:
|
||||
KMonitorProcessIO(QWidget* parent, int pid = -1);
|
||||
~KMonitorProcessIO();
|
||||
|
||||
/** Whether to include the output from child processes. If true, forks and clones will be monitored */
|
||||
bool includeChildProcesses() const;
|
||||
|
||||
/** Interval to poll for new ptrace input. Recommended around 20 (milliseconds). Note that the process
|
||||
* being monitored cannot do anything if it is waiting for us to update.
|
||||
* Default is 20 (ms)
|
||||
*/
|
||||
int updateInterval() const;
|
||||
/** Set interval to poll for new ptrace input. Recommended around 20 (milliseconds). Note that the process
|
||||
* being monitored cannot do anything if it is waiting for us to update.
|
||||
* Default is 20 (ms)
|
||||
*/
|
||||
void setUpdateInterval(int msecs);
|
||||
|
||||
/** Detached state indicates that we are not connected to the process and not monitoring it.
|
||||
*
|
||||
* AttachedRunning state indicates that we are attached to the process and displaying its output.
|
||||
*
|
||||
* AttachedPaused state indicates that we are attached but not reading its output. This will block the process until we resume or detach.
|
||||
*/
|
||||
enum State { Detached, AttachedRunning, AttachedPaused };
|
||||
|
||||
/** Return the current state. */
|
||||
KMonitorProcessIO::State state() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
/** Set whether to include the output from child processes. If true, forks and clones will be monitored */
|
||||
void setIncludeChildProcesses(bool include);
|
||||
/** If the state is in AttachedRunning, change to AttachedPaused. This will block the process until we resume or detach.*/
|
||||
void pauseProcesses();
|
||||
/** If the state is in AttachedPaused, change to AttachedRunning. This will allow the process to run again. */
|
||||
void resumeProcesses();
|
||||
/** Stop monitoring all processes*/
|
||||
void detach();
|
||||
/** Stop monitoring the given process */
|
||||
void detach(int pid);
|
||||
/** Start monitoring the given process. If this is the first process being monitored, the state is set to
|
||||
* AttachedRunning if possible and attachedPid() will return @p pid
|
||||
* @return true if successfully reattached. Can fail if process has disappeared or we do not have the right to attach. */
|
||||
bool attach(int pid);
|
||||
/** Reattach the pid that was first attached.
|
||||
* @return true if successfully reattached. Can fail if process has disappeared or we do not have the right to attach. */
|
||||
bool reattach();
|
||||
/** Return the main pid that we are monitoring.*/
|
||||
int attachedPid() const;
|
||||
/** Attempts to set the state. Check status() to confirm whether the state has changed successfully. */
|
||||
void setState(State new_state);
|
||||
|
||||
Q_SIGNALS:
|
||||
void finished();
|
||||
private Q_SLOTS:
|
||||
/** Read in the next bit of data and display it. This should be called very frequently. */
|
||||
void update(bool modified=false);
|
||||
|
||||
private:
|
||||
KProcess mIOProcess;
|
||||
KTextEditVT *mTextEdit;
|
||||
QTimer mTimer;
|
||||
int mPid;
|
||||
QList<int> attached_pids;
|
||||
|
||||
int mUpdateInterval;
|
||||
bool mIncludeChildProcesses;
|
||||
bool remove_duplicates;
|
||||
|
||||
unsigned int lastdir;
|
||||
QTextCursor mCursor;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
7
ksysguard/processui/KMonitorProcessIO.widgets
Normal file
7
ksysguard/processui/KMonitorProcessIO.widgets
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
[KMonitorProcessIO]
|
||||
ToolTip=Monitors the input and output of a running process.
|
||||
WhatsThis=A widget for showing the input and output of a running process, including stdin, stdout, stderr and any file descriptors. Be careful as this can make the watched process quite slow.
|
||||
Group=KSysGuard (KDE)
|
||||
ConstructorArgs=(parent)
|
||||
IncludeFile=KMonitorProcessIO.h
|
170
ksysguard/processui/KTextEditVT.cpp
Normal file
170
ksysguard/processui/KTextEditVT.cpp
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
KSysGuard, the KDE System Guard
|
||||
|
||||
Copyright (C) 2007 Trent Waddington <trent.waddington@gmail.com>
|
||||
Copyright (c) 2008 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 <klocale.h>
|
||||
#include "KTextEditVT.h"
|
||||
|
||||
#include "KTextEditVT.moc"
|
||||
#include <kglobalsettings.h>
|
||||
|
||||
KTextEditVT::KTextEditVT(QWidget* parent)
|
||||
: QTextEdit( parent )
|
||||
{
|
||||
mParseAnsi = true;
|
||||
escape_sequence = false;
|
||||
escape_CSI = false;
|
||||
escape_OSC = false;
|
||||
escape_number1 = -1;
|
||||
escape_number_seperator = false;
|
||||
escape_number2 = -1;
|
||||
escape_code = 0;
|
||||
setFont( KGlobalSettings::fixedFont() );
|
||||
}
|
||||
|
||||
|
||||
void KTextEditVT::insertVTChar(const QChar & c) {
|
||||
if(escape_sequence) {
|
||||
if(escape_CSI || escape_OSC) {
|
||||
if(c.isDigit()) {
|
||||
if(!escape_number_seperator) {
|
||||
if(escape_number1 == -1)
|
||||
escape_number1 = c.digitValue();
|
||||
else
|
||||
escape_number1 = escape_number1*10 + c.digitValue();
|
||||
} else {
|
||||
if(escape_number2 == -1)
|
||||
escape_number2 = c.digitValue();
|
||||
else
|
||||
escape_number2 = escape_number2*10 + c.digitValue();
|
||||
|
||||
}
|
||||
} else if(c == ';') {
|
||||
escape_number_seperator = true;
|
||||
} else if(escape_OSC && c==7) { //Throw away any letters that are not OSC
|
||||
escape_code = c;
|
||||
} else if(escape_CSI)
|
||||
escape_code = c;
|
||||
} else if(c=='[') {
|
||||
escape_CSI = true;
|
||||
} else if(c==']') {
|
||||
escape_OSC = true;
|
||||
}
|
||||
else if(c=='(' || c==')') {}
|
||||
else
|
||||
escape_code = c;
|
||||
if(!escape_code.isNull()) {
|
||||
//We've read in the whole escape sequence. Now parse it
|
||||
if(escape_code == 'm') { // change color
|
||||
switch(escape_number2){
|
||||
case 0: //all off
|
||||
setFontWeight(QFont::Normal);
|
||||
setTextColor(Qt::black);
|
||||
break;
|
||||
case 1: //bold
|
||||
setFontWeight(QFont::Bold);
|
||||
break;
|
||||
case 31: //red
|
||||
setTextColor(Qt::red);
|
||||
break;
|
||||
case 32: //green
|
||||
setTextColor(Qt::green);
|
||||
break;
|
||||
case 33: //yellow
|
||||
setTextColor(Qt::yellow);
|
||||
break;
|
||||
case 34: //blue
|
||||
setTextColor(Qt::blue);
|
||||
break;
|
||||
case 35: //magenta
|
||||
setTextColor(Qt::magenta);
|
||||
break;
|
||||
case 36: //cyan
|
||||
setTextColor(Qt::cyan);
|
||||
break;
|
||||
case -1:
|
||||
case 30: //black
|
||||
case 39: //reset
|
||||
case 37: //white
|
||||
setTextColor(Qt::black);
|
||||
break;
|
||||
}
|
||||
}
|
||||
escape_code = 0;
|
||||
escape_number1 = -1;
|
||||
escape_number2 = -1;
|
||||
escape_CSI = false;
|
||||
escape_OSC = false;
|
||||
escape_sequence = false;
|
||||
escape_number_seperator = false;
|
||||
}
|
||||
} else if(c == 0x0d) {
|
||||
insertPlainText(QChar('\n'));
|
||||
} else if(c.isPrint() || c == '\n') {
|
||||
insertPlainText(QChar(c));
|
||||
} else if(mParseAnsi) {
|
||||
if(c == 127 || c == 8) { // delete or backspace, respectively
|
||||
textCursor().deletePreviousChar();
|
||||
} else if(c==27) { // escape key
|
||||
escape_sequence = true;
|
||||
} else if(c==0x9b) { // CSI - equivalent to esc [
|
||||
escape_sequence = true;
|
||||
escape_CSI = true;
|
||||
} else if(c==0x9d) { // OSC - equivalent to esc ]
|
||||
escape_sequence = true;
|
||||
escape_OSC = true;
|
||||
}
|
||||
|
||||
} else if(!c.isNull()) {
|
||||
insertPlainText("[");
|
||||
QByteArray num;
|
||||
num.setNum(c.toAscii());
|
||||
insertPlainText(num);
|
||||
insertPlainText("]");
|
||||
}
|
||||
}
|
||||
|
||||
void KTextEditVT::insertVTText(const QByteArray & string)
|
||||
{
|
||||
int size= string.size();
|
||||
for(int i =0; i < size; i++)
|
||||
insertVTChar(QChar(string.at(i)));
|
||||
}
|
||||
|
||||
void KTextEditVT::insertVTText(const QString & string)
|
||||
{
|
||||
int size= string.size();
|
||||
for(int i =0; i < size; i++)
|
||||
insertVTChar(string.at(i));
|
||||
}
|
||||
|
||||
void KTextEditVT::setParseAnsiEscapeCodes(bool parseAnsi)
|
||||
{
|
||||
mParseAnsi = parseAnsi;
|
||||
}
|
||||
|
||||
bool KTextEditVT::parseAnsiEscapeCodes() const
|
||||
{
|
||||
return mParseAnsi;
|
||||
}
|
||||
|
104
ksysguard/processui/KTextEditVT.h
Normal file
104
ksysguard/processui/KTextEditVT.h
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
KSysGuard, the KDE System Guard
|
||||
|
||||
Copyright (c) 2008 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 _KTextEditVT_h_
|
||||
#define _KTextEditVT_h_
|
||||
|
||||
#include <QtGui/QTextEdit>
|
||||
#include <kdemacros.h>
|
||||
|
||||
/*
|
||||
* \class KTextEditVT
|
||||
* \brief The KTextEditVT class provides a widget that is used to edit and display
|
||||
* both plain and rich text with the additional function of being able to
|
||||
* programmatically append VT100 formatted text. For example to display the output
|
||||
* from console programs.
|
||||
*
|
||||
* This class can be used to display the output of VT100 formatted text with
|
||||
* ANSI escape code - for example output from the command 'ls --color'.
|
||||
*
|
||||
* Only a very limited number of ansi escapes sequences will have an affect. Unrecognised
|
||||
* ansi escape sequences will be ignored and not displayed. Patches are welcome to support
|
||||
* more of the sequences.
|
||||
*
|
||||
* This output can be then be inserted at the current cursor position by calling
|
||||
* insertVTText(string);
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* \code
|
||||
* insertVTText(QString("Hi") + QChar(08) + "ello");
|
||||
* \endcode
|
||||
*
|
||||
* will insert the text "Hello" at the current character position.
|
||||
* (Character 08 is the literal backspace character. Treated as equivalent to character 127)
|
||||
*/
|
||||
class KDE_EXPORT KTextEditVT : public QTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( bool parseAnsiEscapeCodes READ parseAnsiEscapeCodes WRITE setParseAnsiEscapeCodes )
|
||||
|
||||
public:
|
||||
KTextEditVT(QWidget* parent);
|
||||
|
||||
/** Whether to parse ANSI display code. If turned off the escape sequence will be shown literally. */
|
||||
bool parseAnsiEscapeCodes() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
/** Set whether to parse ANSI display code. If turned off the escape sequence will be shown literally. */
|
||||
void setParseAnsiEscapeCodes(bool displayall);
|
||||
/** Insert the given string at the current position based on the current state.
|
||||
* This is interpreted in a VT100 encoding. Backspace and delete will delete the previous character,
|
||||
* escape sequences can move the cursor and set the current color etc.
|
||||
*
|
||||
* This just calls insertVTChar for each character in the string
|
||||
*/
|
||||
void insertVTText(const QByteArray & string);
|
||||
/** Insert the given string at the current position based on the current state.
|
||||
* This is interpreted in a VT100 encoding. Backspace and delete will delete the previous character,
|
||||
* escape sequences can move the cursor and set the current color etc.
|
||||
*
|
||||
* This just calls insertVTChar for each character in the string
|
||||
*/
|
||||
void insertVTText(const QString & string);
|
||||
|
||||
/** Insert the given character at the current position based on the current state.
|
||||
* This is interpreted in a VT100 encoding. Backspace and delete will delete the previous character,
|
||||
* escape sequences can move the cursor and set the current color etc.
|
||||
*/
|
||||
void insertVTChar(const QChar & c);
|
||||
|
||||
|
||||
private:
|
||||
bool mParseAnsi;
|
||||
|
||||
bool escape_sequence;
|
||||
bool escape_CSI;
|
||||
bool escape_OSC;
|
||||
int escape_number1;
|
||||
int escape_number2;
|
||||
bool escape_number_seperator;
|
||||
QChar escape_code;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
2
ksysguard/processui/Messages.sh
Executable file
2
ksysguard/processui/Messages.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#! /usr/bin/env bash
|
||||
$XGETTEXT *.cpp *.cc -o $podir/processui.pot
|
149
ksysguard/processui/ProcessFilter.cc
Normal file
149
ksysguard/processui/ProcessFilter.cc
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
KSysGuard, the KDE System Guard
|
||||
|
||||
Copyright (c) 2006-2007 John Tapsell <john.tapsell@kde.org>
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* For getuid() */
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
#include <kdebug.h>
|
||||
|
||||
#include "ProcessModel.h"
|
||||
#include "ProcessModel_p.h"
|
||||
#include "ProcessFilter.h"
|
||||
|
||||
bool ProcessFilter::filterAcceptsRow( int source_row, const QModelIndex & source_parent ) const
|
||||
{
|
||||
if( (mFilter == AllProcesses || mFilter == AllProcessesInTreeForm)
|
||||
&& filterRegExp().isEmpty()) return true; //Shortcut for common case
|
||||
|
||||
ProcessModel *model = static_cast<ProcessModel *>(sourceModel());
|
||||
const KSysGuard::Process *process;
|
||||
if(model->isSimpleMode()) {
|
||||
if(source_parent.isValid()) {
|
||||
kDebug() << "Serious error with data. In simple mode, there should be no children";
|
||||
return true;
|
||||
}
|
||||
process = model->getProcessAtIndex(source_row);
|
||||
} else {
|
||||
KSysGuard::Process *parent_process = NULL;
|
||||
if(source_parent.isValid()) {
|
||||
parent_process = reinterpret_cast<KSysGuard::Process *>(source_parent.internalPointer());
|
||||
Q_ASSERT(parent_process);
|
||||
} else {
|
||||
//if(!model->isSimpleMode()) {
|
||||
parent_process = model->getProcess(0); //Get our 'special' process which should have the root init child
|
||||
Q_ASSERT(parent_process);
|
||||
//}
|
||||
}
|
||||
if(!model->isSimpleMode() && source_row >= parent_process->children.size()) {
|
||||
kDebug() << "Serious error with data. Source row requested for a non existent row. Requested " << source_row << " of " << parent_process->children.size() << " for " << parent_process->pid;
|
||||
return true;
|
||||
}
|
||||
|
||||
process = parent_process->children.at(source_row);
|
||||
}
|
||||
Q_ASSERT(process);
|
||||
long uid = process->uid;
|
||||
long euid = process->euid;
|
||||
|
||||
bool accepted = true;
|
||||
switch(mFilter) {
|
||||
case AllProcesses:
|
||||
case AllProcessesInTreeForm:
|
||||
break;
|
||||
case SystemProcesses:
|
||||
if( uid >= 100 && model->canUserLogin(uid))
|
||||
accepted = false;
|
||||
break;
|
||||
case UserProcesses:
|
||||
if( (uid < 100 || !model->canUserLogin(uid)) && (euid < 100 || !model->canUserLogin(euid)))
|
||||
accepted = false;
|
||||
break;
|
||||
case OwnProcesses: {
|
||||
long ownuid = getuid();
|
||||
if(uid != ownuid && process->suid != ownuid && process->fsuid != ownuid && euid != ownuid)
|
||||
accepted = false;
|
||||
break;
|
||||
}
|
||||
case ProgramsOnly:
|
||||
if(process->tty.isEmpty()) {
|
||||
if(!model->hasGUIWindow(process->pid))
|
||||
accepted = false;
|
||||
} else {
|
||||
// login and getty kinda _are_ the tty, so I do not really count them as 'programs'. So make a special case and hide them
|
||||
// Their ppid are 1 (init) so by checking we try to avoid false matches, and speed up checking overall
|
||||
if(process->parent_pid == 1 && (process->name == "login" || process->name.endsWith("getty")))
|
||||
accepted = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(accepted) {
|
||||
if(filterRegExp().isEmpty()) return true;
|
||||
|
||||
//Allow the user to search by PID
|
||||
if(QString::number(process->pid).contains(filterRegExp())) return true;
|
||||
|
||||
//None of our tests have rejected it. Pass it on to qsortfilterproxymodel's filter
|
||||
if(QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//We did not accept this row at all.
|
||||
|
||||
//If we are in flat mode, then give up now
|
||||
if(mFilter != AllProcessesInTreeForm)
|
||||
return false;
|
||||
|
||||
//one of our children might be accepted, so accept this row if our children are accepted.
|
||||
QModelIndex source_index = sourceModel()->index(source_row, 0, source_parent);
|
||||
for(int i = 0 ; i < sourceModel()->rowCount(source_index); i++) {
|
||||
if(filterAcceptsRow(i, source_index)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProcessFilter::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||
{
|
||||
if(right.isValid() && left.isValid()) {
|
||||
Q_ASSERT(left.model());
|
||||
Q_ASSERT(right.model());
|
||||
QVariant l = (left.model() ? left.model()->data(left, ProcessModel::SortingValueRole) : QVariant());
|
||||
QVariant r = (right.model() ? right.model()->data(right, ProcessModel::SortingValueRole) : QVariant());
|
||||
if(l.isValid() && r.isValid())
|
||||
return l.toDouble() < r.toDouble();
|
||||
}
|
||||
return QSortFilterProxyModel::lessThan(left,right);
|
||||
}
|
||||
|
||||
|
||||
void ProcessFilter::setFilter(State filter) {
|
||||
mFilter = filter;
|
||||
filterChanged();//Tell the proxy view to refresh all its information
|
||||
}
|
||||
#include "ProcessFilter.moc"
|
56
ksysguard/processui/ProcessFilter.h
Normal file
56
ksysguard/processui/ProcessFilter.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
KSysGuard, the KDE System Guard
|
||||
|
||||
Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org>
|
||||
Copyright (c) 2006 John Tapsell <john.tapsell@kdemail.net>
|
||||
|
||||
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 PROCESSFILTER_H_
|
||||
#define PROCESSFILTER_H_
|
||||
|
||||
#include <QtGui/QSortFilterProxyModel>
|
||||
#include <QtCore/QObject>
|
||||
#include <kdemacros.h>
|
||||
|
||||
class QModelIndex;
|
||||
|
||||
class KDE_EXPORT ProcessFilter : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(State)
|
||||
|
||||
public:
|
||||
enum State {AllProcesses=0,AllProcessesInTreeForm, SystemProcesses, UserProcesses, OwnProcesses, ProgramsOnly};
|
||||
ProcessFilter(QObject *parent=0) : QSortFilterProxyModel(parent) {mFilter = AllProcesses;}
|
||||
virtual ~ProcessFilter() {}
|
||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
|
||||
State filter() const {return mFilter; }
|
||||
|
||||
|
||||
public Q_SLOTS:
|
||||
void setFilter(State index);
|
||||
|
||||
protected:
|
||||
virtual bool filterAcceptsRow( int source_row, const QModelIndex & source_parent ) const;
|
||||
|
||||
State mFilter;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
1245
ksysguard/processui/ProcessModel.cc
Normal file
1245
ksysguard/processui/ProcessModel.cc
Normal file
File diff suppressed because it is too large
Load Diff
143
ksysguard/processui/ProcessModel.h
Normal file
143
ksysguard/processui/ProcessModel.h
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
KSysGuard, the KDE System Guard
|
||||
|
||||
Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org>
|
||||
Copyright (c) 2006 John Tapsell <john.tapsell@kde.org>
|
||||
|
||||
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 PROCESSMODEL_H_
|
||||
#define PROCESSMODEL_H_
|
||||
|
||||
#include <QtCore/QAbstractItemModel>
|
||||
|
||||
#include <kdemacros.h>
|
||||
|
||||
namespace KSysGuard {
|
||||
class Processes;
|
||||
class Process;
|
||||
}
|
||||
|
||||
class ProcessModelPrivate;
|
||||
class KDE_EXPORT ProcessModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(Units)
|
||||
|
||||
public:
|
||||
ProcessModel(QObject* parent = 0, const QString &host = QString() );
|
||||
virtual ~ProcessModel();
|
||||
|
||||
/* Functions for our Model for QAbstractItemModel*/
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const;
|
||||
QModelIndex parent ( const QModelIndex & index ) const;
|
||||
|
||||
bool hasChildren ( const QModelIndex & parent) const;
|
||||
|
||||
/* Functions for setting the model */
|
||||
|
||||
/** Setup the column headings by inserting the appropriate headings into the model.
|
||||
* Can be called more than once to retranslate the headings if the system language changes.
|
||||
*/
|
||||
void setupHeader();
|
||||
|
||||
/** Update data. You can pass in the time between updates to only update if there hasn't
|
||||
* been an update within the last @p updateDurationMSecs milliseconds */
|
||||
void update(int updateDurationMSecs = 0);
|
||||
|
||||
/** Return a string with the pid of the process and the name of the process. E.g. 13343: ksyguard
|
||||
*/
|
||||
QString getStringForProcess(KSysGuard::Process *process) const;
|
||||
KSysGuard::Process *getProcess(long long pid);
|
||||
|
||||
/** This is used from ProcessFilter to get the process at a given index when in flat mode */
|
||||
KSysGuard::Process *getProcessAtIndex(int index) const;
|
||||
|
||||
/** Returns whether this user can log in or not.
|
||||
* @see mUidCanLogin
|
||||
*/
|
||||
bool canUserLogin(long long uid) const;
|
||||
/** In simple mode, everything is flat, with no icons, few if any colors, no xres etc.
|
||||
* This can be changed at any time. It is a fairly quick operation. Basically it resets the model
|
||||
*/
|
||||
void setSimpleMode(bool simple);
|
||||
/** In simple mode, everything is flat, with no icons, few if any colors, no xres etc
|
||||
*/
|
||||
bool isSimpleMode() const;
|
||||
|
||||
/** Returns the total amount of physical memory in the machine. */
|
||||
long long totalMemory() const;
|
||||
|
||||
/** This returns a QModelIndex for the given process. It has to look up the parent for this pid, find the offset this
|
||||
* pid is from the parent, and return that. It's not that slow, but does involve a couple of hash table lookups.
|
||||
*/
|
||||
QModelIndex getQModelIndex ( KSysGuard::Process *process, int column) const;
|
||||
|
||||
/** Whether this is showing the processes for the current machine
|
||||
*/
|
||||
bool isLocalhost() const;
|
||||
|
||||
/** The host name that this widget is showing the processes of */
|
||||
QString hostName() const;
|
||||
|
||||
/** Whether this process has a GUI window */
|
||||
bool hasGUIWindow(long long pid) const;
|
||||
|
||||
/** Returns for process controller pointer for this model
|
||||
*/
|
||||
KSysGuard::Processes *processController(); ///The processes instance
|
||||
|
||||
/** The headings in the model. The order here is the order that they are shown
|
||||
* in. If you change this, make sure you also change the
|
||||
* setup header function, and make sure you increase PROCESSHEADERVERSION. This will ensure
|
||||
* that old saved settings won't be used
|
||||
*/
|
||||
#define PROCESSHEADERVERSION 1
|
||||
enum { HeadingName=0, HeadingUser, HeadingPid, HeadingTty, HeadingNiceness, HeadingCPUUsage, HeadingVmSize, HeadingMemory, HeadingSharedMemory, HeadingCommand, HeadingXTitle };
|
||||
enum { UidRole = Qt::UserRole, SortingValueRole, WindowIdRole, TotalMemoryRole, NumberOfProcessorsRole };
|
||||
|
||||
bool showTotals() const;
|
||||
|
||||
/** When displaying memory sizes, this is the units it should be displayed in */
|
||||
enum Units { UnitsKB, UnitsMB, UnitsGB };
|
||||
/** Set the units memory sizes etc should be displayed in */
|
||||
void setUnits(Units units);
|
||||
/** The units memory sizes etc should be displayed in */
|
||||
Units units() const;
|
||||
/** Take an amount in kb, and return a string in the units set by setUnits() */
|
||||
QString formatMemoryInfo(long amountInKB) const;
|
||||
|
||||
/** Retranslate the GUI, for when the system language changes */
|
||||
void retranslateUi();
|
||||
|
||||
public Q_SLOTS:
|
||||
|
||||
/** Whether to show the total cpu for the process plus all of its children */
|
||||
void setShowTotals(bool showTotals);
|
||||
|
||||
private:
|
||||
ProcessModelPrivate* const d;
|
||||
friend class ProcessModelPrivate;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
186
ksysguard/processui/ProcessModel_p.h
Normal file
186
ksysguard/processui/ProcessModel_p.h
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
KSysGuard, the KDE System Guard
|
||||
|
||||
Copyright (c) 2006-2007 John Tapsell <john.tapsell@kde.org>
|
||||
|
||||
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 PROCESSMODEL_P_H_
|
||||
#define PROCESSMODEL_P_H_
|
||||
|
||||
#include <kapplication.h>
|
||||
#include <kuser.h>
|
||||
#include <QPixmap>
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QHash>
|
||||
#include <QSet>
|
||||
#include <QTime>
|
||||
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
#include <kwindowsystem.h>
|
||||
#include <netwm.h>
|
||||
#include <QtGui/QX11Info>
|
||||
#include <X11/Xatom.h>
|
||||
#include <kxerrorhandler.h>
|
||||
#endif
|
||||
|
||||
#include "processcore/process.h"
|
||||
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
struct WindowInfo {
|
||||
QPixmap icon;
|
||||
WId wid;
|
||||
NETWinInfo *netWinInfo;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class ProcessModel;
|
||||
class ProcessModelPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ProcessModelPrivate();
|
||||
~ProcessModelPrivate();
|
||||
public slots:
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
/** When an X window is changed, this is called */
|
||||
void windowChanged(WId wid, unsigned int properties);
|
||||
/** When an X window is created, this is called
|
||||
*/
|
||||
void windowAdded(WId wid);
|
||||
/** When an X window is closed, this is called
|
||||
*/
|
||||
void windowRemoved(WId wid);
|
||||
#endif
|
||||
|
||||
/** Change the data for a process. This is called from KSysGuard::Processes
|
||||
* if @p onlyCpuOrMem is set, only the total cpu usuage is updated.
|
||||
* process->changes contains a bitfield of what has been changed
|
||||
*/
|
||||
void processChanged(KSysGuard::Process *process, bool onlyCpuOrMem);
|
||||
/** Called from KSysGuard::Processes
|
||||
* This indicates we are about to insert a process in the model. Emit the appropriate signals
|
||||
*/
|
||||
void beginInsertRow( KSysGuard::Process *parent);
|
||||
/** Called from KSysGuard::Processes
|
||||
* We have finished inserting a process
|
||||
*/
|
||||
void endInsertRow();
|
||||
/** Called from KSysGuard::Processes
|
||||
* This indicates we are about to remove a process in the model. Emit the appropriate signals
|
||||
*/
|
||||
void beginRemoveRow( KSysGuard::Process *process);
|
||||
/** Called from KSysGuard::Processes
|
||||
* We have finished removing a process
|
||||
*/
|
||||
void endRemoveRow();
|
||||
/** Called from KSysGuard::Processes
|
||||
* This indicates we are about to move a process in the model from one parent process to another. Emit the appropriate signals
|
||||
*/
|
||||
void beginMoveProcess(KSysGuard::Process *process, KSysGuard::Process *new_parent);
|
||||
/** Called from KSysGuard::Processes
|
||||
* We have finished moving a process
|
||||
*/
|
||||
void endMoveRow();
|
||||
|
||||
public:
|
||||
/** On X11 system, connects to the signals emitted when windows are created/destroyed */
|
||||
void setupWindows();
|
||||
/** Connects to the host */
|
||||
void setupProcesses();
|
||||
/** A mapping of running,stopped,etc to a friendly description like 'Stopped, either by a job control signal or because it is being traced.'*/
|
||||
QString getStatusDescription(KSysGuard::Process::ProcessStatus status) const;
|
||||
|
||||
/** Return a qt markup tooltip string for a local user. It will have their full name etc.
|
||||
* This will be slow the first time, as it practically indirectly reads the whole of /etc/passwd
|
||||
* But the second time will be as fast as hash lookup as we cache the result
|
||||
*/
|
||||
inline QString getTooltipForUser(const KSysGuard::Process *process) const;
|
||||
|
||||
/** Return a username for a local user if it can, otherwise just their uid.
|
||||
* This may have been given from the result of "ps" (but not necessarily). If it's not found, then it
|
||||
* needs to find out the username from the uid. This will be slow the first time, as it practically indirectly reads the whole of /etc/passwd
|
||||
* But the second time will be as fast as hash lookup as we cache the result
|
||||
*
|
||||
* If withuid is set, and the username is found, return: "username (Uid: uid)"
|
||||
*/
|
||||
inline QString getUsernameForUser(long long uid, bool withuid) const;
|
||||
|
||||
/** Return the groupname for a given gid. This is in the form of "gid" if not known, or
|
||||
* "groupname (Uid: gid)" if known.
|
||||
*/
|
||||
inline QString getGroupnameForGroup(long long gid) const;
|
||||
/** @see setIsLocalhost */
|
||||
bool mIsLocalhost;
|
||||
|
||||
/** A caching hash for tooltips for a user.
|
||||
* @see getTooltipForUser */
|
||||
mutable QHash<long long,QString> mUserTooltips;
|
||||
|
||||
/** A caching hash for username for a user uid, or just their uid if it can't be found (as a long long)
|
||||
* @see getUsernameForUser */
|
||||
mutable QHash<long long, QString> mUserUsername;
|
||||
|
||||
/** A mapping of a user id to whether this user can log in. We have to guess based on the shell. All are set to true to non localhost.
|
||||
* It is set to:
|
||||
* 0 if the user cannot login
|
||||
* 1 is the user can login
|
||||
* The reason for using an int and not a bool is so that we can do mUidCanLogin.value(uid,-1) and thus we get a tristate for whether
|
||||
* they are logged in, not logged in, or not known yet.
|
||||
* */
|
||||
mutable QHash<long long, int> mUidCanLogin;
|
||||
|
||||
|
||||
/** A translated list of headings (column titles) in the order we want to display them. Used in headerData() */
|
||||
QStringList mHeadings;
|
||||
|
||||
QMultiHash< long long, WindowInfo> mPidToWindowInfo; ///Map a process pid to X window info if available
|
||||
QHash< WId, long long> mWIdToPid; ///Map an X window id to a process pid
|
||||
|
||||
|
||||
bool mShowChildTotals; ///If set to true, a parent will return the CPU usage of all its children recursively
|
||||
|
||||
bool mSimple; ///In simple mode, the model returns everything as flat, with no icons, etc. This is set by changing cmbFilter
|
||||
|
||||
QTime mLastUpdated; ///Time that we last updated the processes.
|
||||
|
||||
long long mMemTotal; /// the total amount of physical memory in kb in the machine. We can used this to determine the percentage of memory an app is using
|
||||
int mNumProcessorCores; /// The number of (enabled) processor cores in the this machine
|
||||
|
||||
KSysGuard::Processes *mProcesses; ///The processes instance
|
||||
|
||||
bool mIsChangingLayout;
|
||||
|
||||
QPixmap mBlankPixmap; ///Used to pad out process names which don't have an icon
|
||||
|
||||
/** When displaying memory sizes, this is the units it should be displayed in */
|
||||
int mUnits;
|
||||
|
||||
/** The hostname */
|
||||
QString mHostName;
|
||||
|
||||
ProcessModel* q;
|
||||
};
|
||||
|
||||
#endif
|
155
ksysguard/processui/ProcessWidgetUI.ui
Normal file
155
ksysguard/processui/ProcessWidgetUI.ui
Normal file
@ -0,0 +1,155 @@
|
||||
<ui version="4.0" >
|
||||
<class>ProcessWidget</class>
|
||||
<widget class="QWidget" name="ProcessWidget" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>490</width>
|
||||
<height>472</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="leftMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnKillProcess" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>&Kill Process</string>
|
||||
</property>
|
||||
<property name="flat" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="KLineEdit" name="txtFilter" >
|
||||
<property name="styleSheet" >
|
||||
<string>QLineEdit { padding-right: 16; }</string>
|
||||
</property>
|
||||
<property name="urlDropsEnabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="clickMessage" >
|
||||
<string>Quick search</string>
|
||||
</property>
|
||||
<property name="showClearButton" stdset="0" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cmbFilter" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maxCount" >
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy" >
|
||||
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>All Processes</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>All Processes, Tree</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>System Processes</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>User Processes</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Own Processes</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Programs Only</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeView" name="treeView" >
|
||||
<property name="editTriggers" >
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="alternatingRowColors" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode" >
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior" >
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="rootIsDecorated" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="uniformRowHeights" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="itemsExpandable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sortingEnabled" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="animated" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="allColumnsShowFocus" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>klineedit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
180
ksysguard/processui/ReniceDlg.cc
Normal file
180
ksysguard/processui/ReniceDlg.cc
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
KSysGuard, the KDE System Guard
|
||||
|
||||
Copyright (c) 1999 Chris Schlaeger <cs@kde.org>
|
||||
Copyright (c) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 <klocale.h>
|
||||
#include <kdebug.h>
|
||||
|
||||
#include "ReniceDlg.moc"
|
||||
#include <QListWidget>
|
||||
#include <QButtonGroup>
|
||||
#include "ui_ReniceDlgUi.h"
|
||||
#include "processcore/process.h"
|
||||
|
||||
ReniceDlg::ReniceDlg(QWidget* parent, const QStringList& processes, int currentCpuPrio, int currentCpuSched, int currentIoPrio, int currentIoSched )
|
||||
: KDialog( parent )
|
||||
{
|
||||
setObjectName( "Renice Dialog" );
|
||||
setModal( true );
|
||||
setCaption( i18n("Renice Process") );
|
||||
setButtons( Ok | Cancel );
|
||||
showButtonSeparator( true );
|
||||
previous_cpuscheduler = 0;
|
||||
|
||||
connect( this, SIGNAL( okClicked() ), SLOT( slotOk() ) );
|
||||
|
||||
if(currentIoSched == KSysGuard::Process::None) {
|
||||
// CurrentIoSched == 0 means that the priority is set automatically.
|
||||
// Using the formula given by the linux kernel Documentation/block/ioprio
|
||||
currentIoPrio = (currentCpuPrio+20)/5;
|
||||
}
|
||||
if(currentIoSched == (int)KSysGuard::Process::BestEffort && currentIoPrio == (currentCpuPrio+20)/5) {
|
||||
// Unfortunately, in linux you can't ever set a process back to being None. So we fake it :)
|
||||
currentIoSched = KSysGuard::Process::None;
|
||||
}
|
||||
ioniceSupported = (currentIoPrio != -2);
|
||||
|
||||
|
||||
QWidget *widget = new QWidget(this);
|
||||
setMainWidget(widget);
|
||||
ui = new Ui_ReniceDlgUi();
|
||||
ui->setupUi(widget);
|
||||
ui->listWidget->insertItems(0, processes);
|
||||
|
||||
cpuScheduler = new QButtonGroup(this);
|
||||
cpuScheduler->addButton(ui->radioNormal, (int)KSysGuard::Process::Other);
|
||||
cpuScheduler->addButton(ui->radioBatch, (int)KSysGuard::Process::Batch);
|
||||
cpuScheduler->addButton(ui->radioFIFO, (int)KSysGuard::Process::Fifo);
|
||||
cpuScheduler->addButton(ui->radioRR, (int)KSysGuard::Process::RoundRobin);
|
||||
if(currentCpuSched >= 0) { //negative means none of these
|
||||
QAbstractButton *sched = cpuScheduler->button(currentCpuSched);
|
||||
if(sched) {
|
||||
sched->setChecked(true); //Check the current scheduler
|
||||
previous_cpuscheduler = currentCpuSched;
|
||||
}
|
||||
}
|
||||
cpuScheduler->setExclusive(true);
|
||||
|
||||
ioScheduler = new QButtonGroup(this);
|
||||
ioScheduler->addButton(ui->radioIONormal, (int)KSysGuard::Process::None);
|
||||
ioScheduler->addButton(ui->radioIdle, (int)KSysGuard::Process::Idle);
|
||||
ioScheduler->addButton(ui->radioRealTime, (int)KSysGuard::Process::RealTime);
|
||||
ioScheduler->addButton(ui->radioBestEffort, (int)KSysGuard::Process::BestEffort);
|
||||
if(currentIoSched >= 0) { //negative means none of these
|
||||
QAbstractButton *iosched = ioScheduler->button(currentIoSched);
|
||||
if(iosched)
|
||||
iosched->setChecked(true); //Check the current io scheduler
|
||||
}
|
||||
|
||||
ioScheduler->setExclusive(true);
|
||||
|
||||
if(ioniceSupported)
|
||||
ui->sliderIO->setValue(currentIoPrio);
|
||||
ui->sliderCPU->setValue(currentCpuPrio);
|
||||
|
||||
ui->imgCPU->setPixmap( KIcon("cpu").pixmap(128, 128) );
|
||||
ui->imgIO->setPixmap( KIcon("drive-harddisk").pixmap(128, 128) );
|
||||
|
||||
newCPUPriority = 40;
|
||||
|
||||
connect(cpuScheduler, SIGNAL(buttonClicked(int)), this, SLOT(cpuSchedulerChanged(int)));
|
||||
connect(ioScheduler, SIGNAL(buttonClicked(int)), this, SLOT(updateUi()));
|
||||
connect(ui->sliderCPU, SIGNAL(valueChanged(int)), this, SLOT(cpuSliderChanged(int)));
|
||||
connect(ui->sliderIO, SIGNAL(valueChanged(int)), this, SLOT(ioSliderChanged(int)));
|
||||
|
||||
updateUi();
|
||||
}
|
||||
|
||||
void ReniceDlg::ioSliderChanged(int value) {
|
||||
ui->sliderIO->setToolTip(QString::number(value));
|
||||
}
|
||||
|
||||
void ReniceDlg::cpuSchedulerChanged(int value) {
|
||||
if(value != previous_cpuscheduler) {
|
||||
if( (value == (int)KSysGuard::Process::Other || value == KSysGuard::Process::Batch) &&
|
||||
(previous_cpuscheduler == (int)KSysGuard::Process::Fifo || previous_cpuscheduler == (int)KSysGuard::Process::RoundRobin)) {
|
||||
int slider = -ui->sliderCPU->value() * 2 / 5 + 20;
|
||||
setSliderRange();
|
||||
ui->sliderCPU->setValue( slider );
|
||||
} else if( (previous_cpuscheduler == (int)KSysGuard::Process::Other || previous_cpuscheduler == KSysGuard::Process::Batch) &&
|
||||
(value == (int)KSysGuard::Process::Fifo || value == (int)KSysGuard::Process::RoundRobin)) {
|
||||
int slider = (-ui->sliderCPU->value() + 20) * 5 / 2;
|
||||
setSliderRange();
|
||||
ui->sliderCPU->setValue( slider );
|
||||
}
|
||||
}
|
||||
previous_cpuscheduler = value;
|
||||
updateUi();
|
||||
}
|
||||
|
||||
void ReniceDlg::cpuSliderChanged(int value) {
|
||||
if(cpuScheduler->checkedId() == (int)KSysGuard::Process::Other || cpuScheduler->checkedId() == (int)KSysGuard::Process::Batch) {
|
||||
if( ioScheduler->checkedId() == -1 || ioScheduler->checkedId() == (int)KSysGuard::Process::None) {
|
||||
//ionice is 'Normal', thus automatically calculated based on cpunice
|
||||
ui->sliderIO->setValue((value+20)/5);
|
||||
}
|
||||
}
|
||||
ui->sliderCPU->setToolTip(QString::number(value));
|
||||
}
|
||||
|
||||
void ReniceDlg::updateUi() {
|
||||
bool cpuPrioEnabled = ( cpuScheduler->checkedId() != -1);
|
||||
bool ioPrioEnabled = ( ioniceSupported && ioScheduler->checkedId() != -1 && ioScheduler->checkedId() != (int)KSysGuard::Process::Idle && ioScheduler->checkedId() != (int)KSysGuard::Process::None);
|
||||
|
||||
ui->sliderCPU->setEnabled(cpuPrioEnabled);
|
||||
ui->lblCpuLow->setEnabled(cpuPrioEnabled);
|
||||
ui->lblCpuHigh->setEnabled(cpuPrioEnabled);
|
||||
|
||||
ui->sliderIO->setEnabled(ioPrioEnabled);
|
||||
ui->lblIOLow->setEnabled(ioPrioEnabled);
|
||||
ui->lblIOHigh->setEnabled(ioPrioEnabled);
|
||||
|
||||
setSliderRange();
|
||||
cpuSliderChanged(ui->sliderCPU->value());
|
||||
ioSliderChanged(ui->sliderIO->value());
|
||||
}
|
||||
|
||||
void ReniceDlg::setSliderRange() {
|
||||
if(cpuScheduler->checkedId() == (int)KSysGuard::Process::Other || cpuScheduler->checkedId() == (int)KSysGuard::Process::Batch) {
|
||||
//The slider is setting the priority, so goes from 19 to -20. We cannot actually do this with a slider, so instead we go from -19 to 20, and negate later
|
||||
if(ui->sliderCPU->value() > 20) ui->sliderCPU->setValue(20);
|
||||
ui->sliderCPU->setInvertedAppearance(true);
|
||||
ui->sliderCPU->setMinimum(-19);
|
||||
ui->sliderCPU->setMaximum(20);
|
||||
ui->sliderCPU->setTickInterval(5);
|
||||
} else {
|
||||
if(ui->sliderCPU->value() < 1) ui->sliderCPU->setValue(1);
|
||||
ui->sliderCPU->setInvertedAppearance(false);
|
||||
ui->sliderCPU->setMinimum(1);
|
||||
ui->sliderCPU->setMaximum(99);
|
||||
ui->sliderCPU->setTickInterval(12);
|
||||
}
|
||||
}
|
||||
|
||||
void ReniceDlg::slotOk()
|
||||
{
|
||||
newCPUPriority = ui->sliderCPU->value();
|
||||
newIOPriority = ui->sliderIO->value();
|
||||
newCPUSched = cpuScheduler->checkedId();
|
||||
newIOSched = ioScheduler->checkedId();
|
||||
}
|
67
ksysguard/processui/ReniceDlg.h
Normal file
67
ksysguard/processui/ReniceDlg.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
KSysGuard, the KDE System Guard
|
||||
|
||||
Copyright (c) 2006-2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 _ReniceDlg_h_
|
||||
#define _ReniceDlg_h_
|
||||
|
||||
#include <kdialog.h>
|
||||
|
||||
class Ui_ReniceDlgUi;
|
||||
class QButtonGroup;
|
||||
|
||||
/**
|
||||
* This class creates and handles a simple dialog to change the scheduling
|
||||
* priority of a process.
|
||||
*/
|
||||
class ReniceDlg : public KDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/** Let the user specify the new priorities of the @p processes given, using the given current values.
|
||||
* @p currentCpuSched The current Cpu Scheduler of the processes. Set to -1 to they have different schedulers
|
||||
* @p currentIoSched The current I/O Scheduler of the processes. Set to -1 to they have different schedulers. Leave as the default -2 if not supported
|
||||
*/
|
||||
ReniceDlg(QWidget* parent, const QStringList& processes, int currentCpuPrio, int currentCpuSched, int currentIoPrio=-2, int currentIoSched=-2);
|
||||
int newCPUPriority;
|
||||
int newIOPriority;
|
||||
int newCPUSched;
|
||||
int newIOSched;
|
||||
|
||||
bool ioniceSupported;
|
||||
|
||||
|
||||
public Q_SLOTS:
|
||||
void slotOk();
|
||||
void updateUi();
|
||||
void cpuSliderChanged(int value);
|
||||
void ioSliderChanged(int value);
|
||||
void cpuSchedulerChanged(int value);
|
||||
private:
|
||||
void setSliderRange();
|
||||
Ui_ReniceDlgUi *ui;
|
||||
QButtonGroup *cpuScheduler;
|
||||
QButtonGroup *ioScheduler;
|
||||
int previous_cpuscheduler;
|
||||
};
|
||||
|
||||
#endif
|
443
ksysguard/processui/ReniceDlgUi.ui
Normal file
443
ksysguard/processui/ReniceDlgUi.ui
Normal file
@ -0,0 +1,443 @@
|
||||
<ui version="4.0" >
|
||||
<class>ReniceDlgUi</class>
|
||||
<widget class="QWidget" name="ReniceDlgUi" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>652</width>
|
||||
<height>397</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="spacing" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblMessage1" >
|
||||
<property name="text" >
|
||||
<string>Change scheduling priority for:</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="contextMenuPolicy" >
|
||||
<enum>Qt::NoContextMenu</enum>
|
||||
</property>
|
||||
<property name="selectionMode" >
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
</property>
|
||||
<property name="uniformItemSizes" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="imgCPU" >
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>128</width>
|
||||
<height>128</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>128</width>
|
||||
<height>128</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="textFormat" >
|
||||
<enum>Qt::AutoText</enum>
|
||||
</property>
|
||||
<property name="pixmap" >
|
||||
<pixmap/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="font" >
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>CPU Scheduler</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioNormal" >
|
||||
<property name="toolTip" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The standard time-sharing scheduler for processes without special requirements.</p></body></html></string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Normal Scheduling: Default Linux time-sharing (Other)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;">Normal<span style=" font-weight:400;"> is the standard Linux time-sharing scheduler that is intended for all processes that do not require special static priority real-time mechanisms. The process to run is chosen from the list of other</span> Normal<span style=" font-weight:400;"> or </span>Batch<span style=" font-weight:400;"> processes based on a dynamic priority that is determined only inside this list. The dynamic priority is based on the priority level given and increased for each time-quantum the process is ready to run, but denied to run by the scheduler. This ensures fair progress among all Normal processes.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Normal</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioBatch" >
|
||||
<property name="toolTip" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For CPU-intensive non-interactive processes. Process is mildly disfavored in scheduling decisions.</p></body></html></string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Batch Scheduling</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><span style=" font-weight:400; font-style:italic;">(Since Linux 2.6.16.)</span><span style=" font-weight:400;"> This policy is similar to </span>Normal<span style=" font-weight:400;">, except that this policy will cause the scheduler to always assume that the process is CPU-intensive. Consequently, the scheduler will apply a small scheduling penalty so that this process is mildly disfavored in scheduling decisions. This policy is useful for workloads that are non-interactive, but do not want to lower their nice value, and for workloads that want a deterministic scheduling policy without interactivity causing extra preemptions (between the workload's tasks).</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Batch</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioRR" >
|
||||
<property name="toolTip" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Process will run whenever runnable. Higher priority than Normal or Batch. Has Timeslicing.</p></body></html></string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Round Robin Scheduling</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Round Robin</span> is a simple enhancement of <span style=" font-weight:600;">FIFO</span>. Everything described below for <span style=" font-weight:600;">FIFO</span> also applies to <span style=" font-weight:600;">Round Robin</span>, except that each process is only allowed to run for a maximum time quantum.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Round Robin</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioFIFO" >
|
||||
<property name="toolTip" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Process will run whenever runnable. Higher priority than Normal or Batch. No timeslicing.</p></body></html></string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">First In-First Out Scheduling</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When a <span style=" font-weight:600;">FIFO</span> process becomes runnable, it will always immediately preempt any currently running <span style=" font-weight:600;">Normal</span> or <span style=" font-weight:600;">Batch</span> process.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>FIFO</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="2" >
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="3" >
|
||||
<widget class="QLabel" name="imgIO" >
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>128</width>
|
||||
<height>128</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>128</width>
|
||||
<height>128</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap" >
|
||||
<pixmap/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4" >
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3" >
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>26</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font" >
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>I/O Scheduler</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioIONormal" >
|
||||
<property name="toolTip" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Process's priority is based on the CPU priority</p></body></html></string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Normal Scheduling</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the same as <span style=" font-weight:600;">Best Effort</span> scheduling, except that the priority is calculated automatically based on the CPU priority. Processes with a higher priority will take priority for access to the hard disk. Programs running at the same <span style=" font-weight:600;">Best Effort/Normal</span> priority are served in a <span style=" font-weight:600;">Round Robin</span> fashion.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Normal</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioIdle" >
|
||||
<property name="toolTip" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Process can only use the hard disk when no other process has used it very recently.</p></body></html></string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Idle Scheduling</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A program running with <span style=" font-weight:600;">Idle</span> I/O priority will only get disk time when no other program has asked for disk I/O for a defined grace period. The impact of <span style=" font-weight:600;">Idle</span> I/O processes on normal system activity should be zero. Priority is not applicable to this scheduling class.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Idle</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioBestEffort" >
|
||||
<property name="toolTip" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Process is given higher priority to access the hard disk than Normal.</p></body></html></string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Best Effort Scheduling</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Processes with a higher priority will take priority for access to the hard disk. Programs running at the same <span style=" font-weight:600;">Best Effort/Normal</span> priority are served in a <span style=" font-weight:600;">Round Robin</span> fashion.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Best Effort</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioRealTime" >
|
||||
<property name="toolTip" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Process gets immediate access to the hard disk whenever needed, regardless of what else is going on.</p></body></html></string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Real Time Scheduling</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The <span style=" font-weight:600;">Real Time</span> scheduling class is given first access to the disk, regardless of what else is going on in the system. Thus the <span style=" font-weight:600;">Real Time</span> class needs to be used with some care, as it can starve other processes. As with the <span style=" font-weight:600;">Best Effort</span> class, 8 priority levels are defined denoting how big a time slice a given process will receive on each scheduling window</p></body></html></string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Real Time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2" >
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" colspan="2" >
|
||||
<widget class="QSlider" name="sliderCPU" >
|
||||
<property name="minimum" >
|
||||
<number>-19</number>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="invertedAppearance" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="tickPosition" >
|
||||
<enum>QSlider::TicksBelow</enum>
|
||||
</property>
|
||||
<property name="tickInterval" >
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="lblCpuLow" >
|
||||
<property name="text" >
|
||||
<string>Low Priority</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLabel" name="lblCpuHigh" >
|
||||
<property name="text" >
|
||||
<string>High Priority</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="2" >
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="3" colspan="2" >
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" colspan="2" >
|
||||
<widget class="QSlider" name="sliderIO" >
|
||||
<property name="maximum" >
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="pageStep" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value" >
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="sliderPosition" >
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="invertedAppearance" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="tickPosition" >
|
||||
<enum>QSlider::TicksBelow</enum>
|
||||
</property>
|
||||
<property name="tickInterval" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="lblIOLow" >
|
||||
<property name="text" >
|
||||
<string>Low Priority</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLabel" name="lblIOHigh" >
|
||||
<property name="text" >
|
||||
<string>High Priority</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11" />
|
||||
<tabstops>
|
||||
<tabstop>listWidget</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
17
ksysguard/processui/ksysguard.widgets
Normal file
17
ksysguard/processui/ksysguard.widgets
Normal file
@ -0,0 +1,17 @@
|
||||
[Global]
|
||||
PluginName=KSysGuardWidgets
|
||||
|
||||
|
||||
[KSysGuardProcessList]
|
||||
ToolTip=A list of processes (programs) running.
|
||||
WhatsThis=A widget for showing all the processes running along with their memory usage and other details.
|
||||
Group=KSysGuard (KDE)
|
||||
ConstructorArgs=(parent)
|
||||
IncludeFile=ksysguardprocesslist.h
|
||||
|
||||
[KTextEditVT]
|
||||
ToolTip=A text box suitable for displaying output from VT console-based programs.
|
||||
WhatsThis=A widget for displaying out from console based programs. Some VT100 style commands are interpreted (For example to change the color) as well as some non-printable characters (backspace/delete etc will delete the last character.). For example the output from 'ls --color' can be displayed.
|
||||
Group=KSysGuard (KDE)
|
||||
ConstructorArgs=(parent)
|
||||
IncludeFile=KTextEditVT.h
|
1140
ksysguard/processui/ksysguardprocesslist.cpp
Normal file
1140
ksysguard/processui/ksysguardprocesslist.cpp
Normal file
File diff suppressed because it is too large
Load Diff
202
ksysguard/processui/ksysguardprocesslist.h
Normal file
202
ksysguard/processui/ksysguardprocesslist.h
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
KSysGuard, the KDE System Guard
|
||||
|
||||
Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org>
|
||||
Copyright (c) 2006 John Tapsell <john.tapsell@kde.org>
|
||||
|
||||
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 _KSysGuardProcessList_h_
|
||||
#define _KSysGuardProcessList_h_
|
||||
|
||||
#include <QtGui/QWidget>
|
||||
#include <kapplication.h>
|
||||
#include "ProcessModel.h"
|
||||
#include "ProcessFilter.h"
|
||||
#include "processes.h"
|
||||
|
||||
class QShowEvent;
|
||||
class QHideEvent;
|
||||
class QLineEdit;
|
||||
class QTreeView;
|
||||
struct KSysGuardProcessListPrivate;
|
||||
extern KApplication* Kapp;
|
||||
|
||||
/**
|
||||
* This widget implements a process list page. Besides the process
|
||||
* list which is implemented as a ProcessList, it contains two
|
||||
* comboxes and two buttons. The combo boxes are used to set the
|
||||
* update rate and the process filter. The buttons are used to force
|
||||
* an immediate update and to kill a process.
|
||||
*/
|
||||
class KDE_EXPORT KSysGuardProcessList : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( bool showTotalsInTree READ showTotals WRITE setShowTotals )
|
||||
Q_PROPERTY( ProcessFilter::State state READ state WRITE setState )
|
||||
Q_PROPERTY( int updateIntervalMSecs READ updateIntervalMSecs WRITE setUpdateIntervalMSecs )
|
||||
Q_PROPERTY( ProcessModel::Units units READ units WRITE setUnits )
|
||||
Q_ENUMS( ProcessFilter::State )
|
||||
Q_ENUMS( ProcessModel::Units )
|
||||
|
||||
public:
|
||||
KSysGuardProcessList(QWidget* parent, const QString &hostName = QString());
|
||||
virtual ~KSysGuardProcessList();
|
||||
|
||||
QLineEdit *filterLineEdit() const;
|
||||
QTreeView *treeView() const;
|
||||
|
||||
/** Returns which processes we are currently filtering for and the way in which we show them.
|
||||
* @see setState()
|
||||
*/
|
||||
ProcessFilter::State state() const;
|
||||
|
||||
/** Returns the number of milliseconds that have to elapse before updating the list of processes */
|
||||
int updateIntervalMSecs() const;
|
||||
|
||||
/** Whether the widget will show child totals for CPU and Memory etc usage */
|
||||
bool showTotals() const;
|
||||
|
||||
/** The units to display memory sizes etc in. E.g. kb/mb/gb */
|
||||
ProcessModel::Units units() const;
|
||||
|
||||
/** Returns a list of the processes that have been selected by the user. */
|
||||
QList<KSysGuard::Process *> selectedProcesses() const;
|
||||
|
||||
/** Save the current state of the widget to the given config group
|
||||
*
|
||||
* @param[in] cg Config group to add these settings to
|
||||
* */
|
||||
void saveSettings(KConfigGroup &cg);
|
||||
|
||||
/** Load the saved state of the widget from the given config group */
|
||||
void loadSettings(const KConfigGroup &cg);
|
||||
|
||||
/** Returns the process model used. Use with caution. */
|
||||
ProcessModel *processModel();
|
||||
|
||||
/** Restore the headings to the given state. */
|
||||
void restoreHeaderState(const QByteArray & state);
|
||||
|
||||
public Q_SLOTS:
|
||||
/** Inform the view that the user has changed the selection */
|
||||
void selectionChanged();
|
||||
|
||||
/** Send a kill signal to all the processes that the user has selected. Pops up a dialog box to confirm with the user */
|
||||
void killSelectedProcesses();
|
||||
|
||||
/** Send a signal to a list of given processes.
|
||||
* @p pids A list of PIDs that should be sent the signal
|
||||
* @p sig The signal to send.
|
||||
* @return Whether the kill went ahead. True if successful or user cancelled. False if there was a problem
|
||||
*/
|
||||
bool killProcesses(const QList< long long> &pids, int sig);
|
||||
|
||||
/** Renice all the processes that the user has selected. Pops up a dialog box to ask for the nice value and confirm */
|
||||
void reniceSelectedProcesses();
|
||||
|
||||
/** Change the CPU scheduler for the given of processes to the given scheduler, with the given scheduler priority.
|
||||
* If the scheduler is Other or Batch, @p newCpuSchedPriority is ignored.
|
||||
* @return Whether the cpu scheduler changing went ahead. True if successful or user cancelled. False if there was a problem
|
||||
*/
|
||||
bool changeCpuScheduler(const QList< long long> &pids, KSysGuard::Process::Scheduler newCpuSched, int newCpuSchedPriority);
|
||||
|
||||
/** Change the I/O scheduler for the given of processes to the given scheduler, with the given scheduler priority.
|
||||
* If the scheduler is Other or Batch, @p newCpuSchedPriority is ignored.
|
||||
* @return Whether the cpu scheduler changing went ahead. True if successful or user cancelled. False if there was a problem
|
||||
*/
|
||||
bool changeIoScheduler(const QList< long long> &pids, KSysGuard::Process::IoPriorityClass newIoSched, int newIoSchedPriority);
|
||||
/** Renice the processes given to the given niceValue.
|
||||
* @return Whether the kill went ahead. True if successful or user cancelled. False if there was a problem
|
||||
* */
|
||||
bool reniceProcesses(const QList<long long> &pids, int niceValue);
|
||||
|
||||
/** Fetch new process information and redraw the display */
|
||||
void updateList();
|
||||
|
||||
/** Set which processes we are currently filtering for and the way in which we show them. */
|
||||
void setState(ProcessFilter::State state);
|
||||
|
||||
/** Set the number of milliseconds that have to elapse before updating the list of processes */
|
||||
void setUpdateIntervalMSecs(int intervalMSecs);
|
||||
|
||||
/** Set whether to show child totals for CPU and Memory etc usage */
|
||||
void setShowTotals(bool showTotals);
|
||||
|
||||
/** Focus on a particular process, and select it */
|
||||
void selectAndJumpToProcess(int pid);
|
||||
|
||||
/** The units to display memory sizes etc in. */
|
||||
void setUnits(ProcessModel::Units unit);
|
||||
|
||||
/** Row was just inserted in the filter model */
|
||||
void rowsInserted ( const QModelIndex & parent, int start, int end );
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
/** Expand all the children, recursively, of the node given. Pass an empty QModelIndex to expand all the top level children */
|
||||
void expandAllChildren(const QModelIndex &parent);
|
||||
|
||||
/** Expand init to show its children, but not the sub children processes. */
|
||||
void expandInit();
|
||||
|
||||
/** Display a context menu for the column headings allowing the user to show or hide columns. */
|
||||
void showColumnContextMenu(const QPoint &point);
|
||||
|
||||
/** Display a context menu for the given process allowing the user to kill etc the process */
|
||||
void showProcessContextMenu(const QModelIndex &index);
|
||||
/** Display a context menu for the selected processes allowing the user to kill etc the process */
|
||||
void showProcessContextMenu(const QPoint &point);
|
||||
|
||||
/** Handle the situation where killing a process has failed - usually due to insufficent rights */
|
||||
void killFailed();
|
||||
|
||||
/** Handle the situation where renicing a process has failed - usually due to insufficent rights */
|
||||
void reniceFailed();
|
||||
|
||||
/** Handle the situation where ionice'ing a process has failed - usually due to insufficent rights */
|
||||
void ioniceFailed();
|
||||
|
||||
/** Set state from combo box int value */
|
||||
void setStateInt(int state);
|
||||
|
||||
/** Called when the text in the gui filter text box has changed */
|
||||
void filterTextChanged(const QString &newText);
|
||||
|
||||
/** Called when one of the actions (kill, renice etc) is clicked etc */
|
||||
void actionTriggered(QObject *object);
|
||||
protected:
|
||||
/** Inherit QWidget::showEvent(QShowEvent *) to enable the timer, for updates, when visible */
|
||||
virtual void showEvent(QShowEvent*);
|
||||
|
||||
/** Inherit QWidget::hideEvent(QShowEvent *) to disable the timer, for updates, when not visible */
|
||||
virtual void hideEvent(QHideEvent*);
|
||||
|
||||
/** Capture any change events sent to this widget. In particular QEvent::LanguageChange */
|
||||
virtual void changeEvent ( QEvent * event );
|
||||
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
|
||||
/** Retranslate the Ui as needed */
|
||||
void retranslateUi();
|
||||
|
||||
private:
|
||||
KSysGuardProcessListPrivate* const d;
|
||||
};
|
||||
|
||||
#endif
|
12
ksysguard/tests/CMakeLists.txt
Normal file
12
ksysguard/tests/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
||||
set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
|
||||
|
||||
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../processcore/ )
|
||||
|
||||
|
||||
kde4_add_unit_test(processtest processtest.cpp)
|
||||
|
||||
target_link_libraries(processtest processcore ${KDE4_KDECORE_LIBS} ${QT_QTTEST_LIBRARY})
|
||||
|
||||
|
||||
|
47
ksysguard/tests/guitest.cpp
Normal file
47
ksysguard/tests/guitest.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/* This file is part of the KDE project
|
||||
Copyright (C) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 <QtTest>
|
||||
#include <QtCore>
|
||||
|
||||
#include <klocale.h>
|
||||
#include <kdebug.h>
|
||||
#include <qtest_kde.h>
|
||||
|
||||
#include <processui/ksysguardprocesslist.h>
|
||||
|
||||
#include "guitest.h"
|
||||
|
||||
void testGuiProcess::testGUI() {
|
||||
KSysGuardProcessList processlist(NULL);
|
||||
|
||||
QTime t;
|
||||
t.start();
|
||||
|
||||
for(int i =0; i < 10; i++) {
|
||||
processlist.updateList();
|
||||
}
|
||||
kDebug() << "time taken: " << t.elapsed() << "ms";
|
||||
}
|
||||
|
||||
QTEST_KDEMAIN(testGuiProcess, GUI)
|
||||
|
||||
#include "guitest.moc"
|
||||
|
32
ksysguard/tests/guitest.h
Normal file
32
ksysguard/tests/guitest.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* This file is part of the KDE project
|
||||
Copyright (C) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 GUITESTPROCESS_H
|
||||
#define GUITESTPROCESS_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
class testGuiProcess: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void testGUI();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
124
ksysguard/tests/processtest.cpp
Normal file
124
ksysguard/tests/processtest.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
/* This file is part of the KDE project
|
||||
Copyright (C) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 <QtTest>
|
||||
#include <QtCore>
|
||||
|
||||
#include <klocale.h>
|
||||
#include <qtest_kde.h>
|
||||
#include <kdebug.h>
|
||||
|
||||
#include "processcore/processes.h"
|
||||
#include "processcore/process.h"
|
||||
|
||||
#include "processtest.h"
|
||||
|
||||
void testProcess::testProcesses() {
|
||||
KSysGuard::Processes *processController = KSysGuard::Processes::getInstance();
|
||||
processController->updateAllProcesses();
|
||||
QList<KSysGuard::Process *> processes = processController->getAllProcesses();
|
||||
QSet<long> pids;
|
||||
foreach( KSysGuard::Process *process, processes) {
|
||||
if(process->pid == 0) continue;
|
||||
QVERIFY(process->pid > 0);
|
||||
QVERIFY(!process->name.isEmpty());
|
||||
|
||||
//test all the pids are unique
|
||||
QVERIFY(!pids.contains(process->pid));
|
||||
pids.insert(process->pid);
|
||||
}
|
||||
processController->updateAllProcesses();
|
||||
QList<KSysGuard::Process *> processes2 = processController->getAllProcesses();
|
||||
foreach( KSysGuard::Process *process, processes2) {
|
||||
if(process->pid == 0) continue;
|
||||
QVERIFY(process->pid > 0);
|
||||
QVERIFY(!process->name.isEmpty());
|
||||
|
||||
//test all the pids are unique
|
||||
if(!pids.contains(process->pid)) {
|
||||
kDebug() << process->pid << " not found. " << process->name;
|
||||
}
|
||||
pids.remove(process->pid);
|
||||
}
|
||||
|
||||
QVERIFY(processes2.size() == processes.size());
|
||||
QCOMPARE(processes, processes2); //Make sure calling it twice gives the same results. The difference in time is so small that it really shouldn't have changed
|
||||
}
|
||||
|
||||
|
||||
unsigned long testProcess::countNumChildren(KSysGuard::Process *p) {
|
||||
unsigned long total = p->children.size();
|
||||
for(int i =0; i < p->children.size(); i++) {
|
||||
total += countNumChildren(p->children[i]);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
void testProcess::testProcessesTreeStructure() {
|
||||
KSysGuard::Processes *processController = KSysGuard::Processes::getInstance();
|
||||
processController->updateAllProcesses();
|
||||
QList<KSysGuard::Process *> processes = processController->getAllProcesses();
|
||||
|
||||
foreach( KSysGuard::Process *process, processes) {
|
||||
QCOMPARE(countNumChildren(process), process->numChildren);
|
||||
|
||||
for(int i =0; i < process->children.size(); i++) {
|
||||
QVERIFY(process->children[i]->parent);
|
||||
QCOMPARE(process->children[i]->parent, process);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void testProcess::testProcessesModification() {
|
||||
//We will modify the tree, then re-call getProcesses and make sure that it fixed everything we modified
|
||||
KSysGuard::Processes *processController = KSysGuard::Processes::getInstance();
|
||||
processController->updateAllProcesses();
|
||||
KSysGuard::Process *initProcess = processController->getProcess(1);
|
||||
|
||||
if(!initProcess || initProcess->numChildren < 3)
|
||||
return;
|
||||
|
||||
QVERIFY(initProcess);
|
||||
QVERIFY(initProcess->children[0]);
|
||||
QVERIFY(initProcess->children[1]);
|
||||
kDebug() << initProcess->numChildren;
|
||||
initProcess->children[0]->parent = initProcess->children[1];
|
||||
initProcess->children[1]->children.append(initProcess->children[0]);
|
||||
initProcess->children[1]->numChildren++;
|
||||
initProcess->numChildren--;
|
||||
initProcess->children.removeAt(0);
|
||||
}
|
||||
|
||||
void testProcess::testTime() {
|
||||
//See how long it takes to get proccess information
|
||||
KSysGuard::Processes *processController = KSysGuard::Processes::getInstance();
|
||||
QTime t;
|
||||
t.start();
|
||||
for(int i =0; i < 100; i++)
|
||||
processController->updateAllProcesses();
|
||||
kDebug() << "Time elapsed: "<< t.elapsed() <<" ms, so " << t.elapsed()/100 << "ms" << endl;
|
||||
QVERIFY(t.elapsed()/100 < 300); //It should take less than about 100ms. Anything longer than 300ms even on a slow system really needs to be optimised
|
||||
}
|
||||
|
||||
QTEST_KDEMAIN_CORE(testProcess)
|
||||
|
||||
#include "processtest.moc"
|
||||
|
41
ksysguard/tests/processtest.h
Normal file
41
ksysguard/tests/processtest.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* This file is part of the KDE project
|
||||
Copyright (C) 2007 John Tapsell <tapsell@kde.org>
|
||||
|
||||
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 TESTPROCESS_H
|
||||
#define TESTPROCESS_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
namespace KSysGuard
|
||||
{
|
||||
class Process;
|
||||
}
|
||||
class testProcess: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
unsigned long countNumChildren(KSysGuard::Process *p);
|
||||
private slots:
|
||||
void testTime();
|
||||
void testProcesses();
|
||||
void testProcessesTreeStructure();
|
||||
void testProcessesModification();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
28
kworkspace/CMakeLists.txt
Normal file
28
kworkspace/CMakeLists.txt
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
|
||||
set(kworkspace_LIB_SRCS kdisplaymanager.cpp
|
||||
kworkspace.cpp
|
||||
kwindowlistmenu.cpp
|
||||
)
|
||||
|
||||
set(ksmserver_xml ${KDEBASE_WORKSPACE_SOURCE_DIR}/ksmserver/org.kde.KSMServerInterface.xml)
|
||||
qt4_add_dbus_interface( kworkspace_LIB_SRCS ${ksmserver_xml} ksmserver_interface )
|
||||
|
||||
set(kwin_xml ${KDEBASE_WORKSPACE_SOURCE_DIR}/kwin/org.kde.KWin.xml)
|
||||
|
||||
set_source_files_properties(${kwin_xml} PROPERTIES INCLUDE "interface_util.h")
|
||||
|
||||
qt4_add_dbus_interface( kworkspace_LIB_SRCS ${kwin_xml} kwin_interface )
|
||||
|
||||
|
||||
kde4_add_library(kworkspace SHARED ${kworkspace_LIB_SRCS})
|
||||
|
||||
target_link_libraries(kworkspace ${KDE4_KDEUI_LIBS} ${X11_LIBRARIES} )
|
||||
|
||||
set_target_properties(kworkspace PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} )
|
||||
install(TARGETS kworkspace ${INSTALL_TARGETS_DEFAULT_ARGS} )
|
||||
|
||||
install( FILES kdisplaymanager.h
|
||||
kworkspace.h
|
||||
kwindowlistmenu.h
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/kworkspace COMPONENT Devel )
|
21
kworkspace/Mainpage.dox
Normal file
21
kworkspace/Mainpage.dox
Normal file
@ -0,0 +1,21 @@
|
||||
/** @mainpage Workspace library
|
||||
|
||||
libkworkspace provides functions to allow you to interact with the
|
||||
%KDE session manager.
|
||||
|
||||
@authors
|
||||
Matthias Kalle Dalheimer \<kalle@kde.org\><br>
|
||||
Oswald Buddenhagen \<ossi@kde.org\><br>
|
||||
Matthias Elter \<elter@kde.org\><br>
|
||||
Matthias Ettrich \<ettrich@kde.org\>
|
||||
|
||||
@maintainers
|
||||
[Unknown/None]
|
||||
|
||||
@licenses
|
||||
@lgpl
|
||||
|
||||
*/
|
||||
|
||||
// DOXYGEN_SET_PROJECT_NAME = libkworkspace
|
||||
// vim:ts=4:sw=4:expandtab:filetype=doxygen
|
2
kworkspace/Messages.sh
Normal file
2
kworkspace/Messages.sh
Normal file
@ -0,0 +1,2 @@
|
||||
#! /usr/bin/env bash
|
||||
$XGETTEXT *.cpp -o $podir/libkworkspace.pot
|
26
kworkspace/interface_util.h
Normal file
26
kworkspace/interface_util.h
Normal file
@ -0,0 +1,26 @@
|
||||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2008 Laurent Montel <montel@kde.org>
|
||||
|
||||
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 INTERFACEUTIL_H
|
||||
#define INTERFACEUTIL_H
|
||||
|
||||
|
||||
// needed by the DBUS interface
|
||||
Q_DECLARE_METATYPE(QList<int>)
|
||||
#endif
|
458
kworkspace/kdisplaymanager.cpp
Normal file
458
kworkspace/kdisplaymanager.cpp
Normal file
@ -0,0 +1,458 @@
|
||||
/*
|
||||
Copyright (C) 2004 Oswald Buddenhagen <ossi@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the Lesser 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 Lesser GNU General Public License
|
||||
along with this program; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "kdisplaymanager.h"
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
|
||||
#include <kapplication.h>
|
||||
#include <klocale.h>
|
||||
#include <QtDBus/QtDBus>
|
||||
|
||||
#include <QRegExp>
|
||||
|
||||
#include <X11/Xauth.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static enum { Dunno, NoDM, NewKDM, OldKDM, GDM } DMType = Dunno;
|
||||
static const char *ctl, *dpy;
|
||||
|
||||
class KDisplayManager::Private
|
||||
{
|
||||
public:
|
||||
Private() : fd(-1) {}
|
||||
~Private() {
|
||||
if (fd >= 0)
|
||||
close( fd );
|
||||
}
|
||||
|
||||
int fd;
|
||||
};
|
||||
|
||||
KDisplayManager::KDisplayManager() : d(new Private)
|
||||
{
|
||||
const char *ptr;
|
||||
struct sockaddr_un sa;
|
||||
|
||||
if (DMType == Dunno) {
|
||||
if (!(dpy = ::getenv( "DISPLAY" )))
|
||||
DMType = NoDM;
|
||||
else if ((ctl = ::getenv( "DM_CONTROL" )))
|
||||
DMType = NewKDM;
|
||||
else if ((ctl = ::getenv( "XDM_MANAGED" )) && ctl[0] == '/')
|
||||
DMType = OldKDM;
|
||||
else if (::getenv( "GDMSESSION" ))
|
||||
DMType = GDM;
|
||||
else
|
||||
DMType = NoDM;
|
||||
}
|
||||
switch (DMType) {
|
||||
default:
|
||||
return;
|
||||
case NewKDM:
|
||||
case GDM:
|
||||
if ((d->fd = ::socket( PF_UNIX, SOCK_STREAM, 0 )) < 0)
|
||||
return;
|
||||
sa.sun_family = AF_UNIX;
|
||||
if (DMType == GDM) {
|
||||
strcpy( sa.sun_path, "/var/run/gdm_socket" );
|
||||
if (::connect( d->fd, (struct sockaddr *)&sa, sizeof(sa) )) {
|
||||
strcpy( sa.sun_path, "/tmp/.gdm_socket" );
|
||||
if (::connect( d->fd, (struct sockaddr *)&sa, sizeof(sa) )) {
|
||||
::close( d->fd );
|
||||
d->fd = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
GDMAuthenticate();
|
||||
} else {
|
||||
if ((ptr = strchr( dpy, ':' )))
|
||||
ptr = strchr( ptr, '.' );
|
||||
snprintf( sa.sun_path, sizeof(sa.sun_path),
|
||||
"%s/dmctl-%.*s/socket",
|
||||
ctl, ptr ? int(ptr - dpy) : 512, dpy );
|
||||
if (::connect( d->fd, (struct sockaddr *)&sa, sizeof(sa) )) {
|
||||
::close( d->fd );
|
||||
d->fd = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OldKDM:
|
||||
{
|
||||
QString tf( ctl );
|
||||
tf.truncate( tf.indexOf( ',' ) );
|
||||
d->fd = ::open( tf.toLatin1(), O_WRONLY );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
KDisplayManager::~KDisplayManager()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool
|
||||
KDisplayManager::exec( const char *cmd )
|
||||
{
|
||||
QByteArray buf;
|
||||
|
||||
return exec( cmd, buf );
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a KDM/GDM remote control command.
|
||||
* @param cmd the command to execute. FIXME: undocumented yet.
|
||||
* @param buf the result buffer.
|
||||
* @return result:
|
||||
* @li If true, the command was successfully executed.
|
||||
* @p ret might contain addional results.
|
||||
* @li If false and @p ret is empty, a communication error occurred
|
||||
* (most probably KDM is not running).
|
||||
* @li If false and @p ret is non-empty, it contains the error message
|
||||
* from KDM.
|
||||
*/
|
||||
bool
|
||||
KDisplayManager::exec( const char *cmd, QByteArray &buf )
|
||||
{
|
||||
bool ret = false;
|
||||
int tl;
|
||||
int len = 0;
|
||||
|
||||
if (d->fd < 0)
|
||||
goto busted;
|
||||
|
||||
tl = strlen( cmd );
|
||||
if (::write( d->fd, cmd, tl ) != tl) {
|
||||
bust:
|
||||
::close( d->fd );
|
||||
d->fd = -1;
|
||||
busted:
|
||||
buf.resize( 0 );
|
||||
return false;
|
||||
}
|
||||
if (DMType == OldKDM) {
|
||||
buf.resize( 0 );
|
||||
return true;
|
||||
}
|
||||
for (;;) {
|
||||
if (buf.size() < 128)
|
||||
buf.resize( 128 );
|
||||
else if (buf.size() < len * 2)
|
||||
buf.resize( len * 2 );
|
||||
if ((tl = ::read( d->fd, buf.data() + len, buf.size() - len)) <= 0) {
|
||||
if (tl < 0 && errno == EINTR)
|
||||
continue;
|
||||
goto bust;
|
||||
}
|
||||
len += tl;
|
||||
if (buf[len - 1] == '\n') {
|
||||
buf[len - 1] = 0;
|
||||
if (len > 2 && (buf[0] == 'o' || buf[0] == 'O') &&
|
||||
(buf[1] == 'k' || buf[1] == 'K') && buf[2] <= ' ')
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
KDisplayManager::canShutdown()
|
||||
{
|
||||
if (DMType == OldKDM)
|
||||
return strstr( ctl, ",maysd" ) != 0;
|
||||
|
||||
QByteArray re;
|
||||
|
||||
if (DMType == GDM)
|
||||
return exec( "QUERY_LOGOUT_ACTION\n", re ) && re.indexOf( "HALT" ) >= 0;
|
||||
|
||||
return exec( "caps\n", re ) && re.indexOf( "\tshutdown" ) >= 0;
|
||||
}
|
||||
|
||||
void
|
||||
KDisplayManager::shutdown( KWorkSpace::ShutdownType shutdownType,
|
||||
KWorkSpace::ShutdownMode shutdownMode, /* NOT Default */
|
||||
const QString &bootOption )
|
||||
{
|
||||
if (shutdownType == KWorkSpace::ShutdownTypeNone)
|
||||
return;
|
||||
|
||||
bool cap_ask;
|
||||
if (DMType == NewKDM) {
|
||||
QByteArray re;
|
||||
cap_ask = exec( "caps\n", re ) && re.indexOf( "\tshutdown ask" ) >= 0;
|
||||
} else {
|
||||
if (!bootOption.isEmpty())
|
||||
return;
|
||||
cap_ask = false;
|
||||
}
|
||||
if (!cap_ask && shutdownMode == KWorkSpace::ShutdownModeInteractive)
|
||||
shutdownMode = KWorkSpace::ShutdownModeForceNow;
|
||||
|
||||
QByteArray cmd;
|
||||
if (DMType == GDM) {
|
||||
cmd.append( shutdownMode == KWorkSpace::ShutdownModeForceNow ?
|
||||
"SET_LOGOUT_ACTION " : "SET_SAFE_LOGOUT_ACTION " );
|
||||
cmd.append( shutdownType == KWorkSpace::ShutdownTypeReboot ?
|
||||
"REBOOT\n" : "HALT\n" );
|
||||
} else {
|
||||
cmd.append( "shutdown\t" );
|
||||
cmd.append( shutdownType == KWorkSpace::ShutdownTypeReboot ?
|
||||
"reboot\t" : "halt\t" );
|
||||
if (!bootOption.isEmpty())
|
||||
cmd.append( "=" ).append( bootOption.toLocal8Bit() ).append( "\t" );
|
||||
cmd.append( shutdownMode == KWorkSpace::ShutdownModeInteractive ?
|
||||
"ask\n" :
|
||||
shutdownMode == KWorkSpace::ShutdownModeForceNow ?
|
||||
"forcenow\n" :
|
||||
shutdownMode == KWorkSpace::ShutdownModeTryNow ?
|
||||
"trynow\n" : "schedule\n" );
|
||||
}
|
||||
exec( cmd.data() );
|
||||
}
|
||||
|
||||
bool
|
||||
KDisplayManager::bootOptions( QStringList &opts, int &defopt, int ¤t )
|
||||
{
|
||||
if (DMType != NewKDM)
|
||||
return false;
|
||||
|
||||
QByteArray re;
|
||||
if (!exec( "listbootoptions\n", re ))
|
||||
return false;
|
||||
|
||||
opts = QString::fromLocal8Bit( re.data() ).split( '\t', QString::SkipEmptyParts );
|
||||
if (opts.size() < 4)
|
||||
return false;
|
||||
|
||||
bool ok;
|
||||
defopt = opts[2].toInt( &ok );
|
||||
if (!ok)
|
||||
return false;
|
||||
current = opts[3].toInt( &ok );
|
||||
if (!ok)
|
||||
return false;
|
||||
|
||||
opts = opts[1].split( ' ', QString::SkipEmptyParts );
|
||||
for (QStringList::Iterator it = opts.begin(); it != opts.end(); ++it)
|
||||
(*it).replace( "\\s", " " );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
KDisplayManager::setLock( bool on )
|
||||
{
|
||||
if (DMType != GDM)
|
||||
exec( on ? "lock\n" : "unlock\n" );
|
||||
}
|
||||
|
||||
bool
|
||||
KDisplayManager::isSwitchable()
|
||||
{
|
||||
if (DMType == OldKDM)
|
||||
return dpy[0] == ':';
|
||||
|
||||
if (DMType == GDM)
|
||||
return exec( "QUERY_VT\n" );
|
||||
|
||||
QByteArray re;
|
||||
|
||||
return exec( "caps\n", re ) && re.indexOf( "\tlocal" ) >= 0;
|
||||
}
|
||||
|
||||
int
|
||||
KDisplayManager::numReserve()
|
||||
{
|
||||
if (DMType == GDM)
|
||||
return 1; /* Bleh */
|
||||
|
||||
if (DMType == OldKDM)
|
||||
return strstr( ctl, ",rsvd" ) ? 1 : -1;
|
||||
|
||||
QByteArray re;
|
||||
int p;
|
||||
|
||||
if (!(exec( "caps\n", re ) && (p = re.indexOf( "\treserve " )) >= 0))
|
||||
return -1;
|
||||
return atoi( re.data() + p + 9 );
|
||||
}
|
||||
|
||||
void
|
||||
KDisplayManager::startReserve()
|
||||
{
|
||||
if (DMType == GDM)
|
||||
exec("FLEXI_XSERVER\n");
|
||||
else
|
||||
exec("reserve\n");
|
||||
}
|
||||
|
||||
bool
|
||||
KDisplayManager::localSessions( SessList &list )
|
||||
{
|
||||
if (DMType == OldKDM)
|
||||
return false;
|
||||
|
||||
QByteArray re;
|
||||
|
||||
if (DMType == GDM) {
|
||||
if (!exec( "CONSOLE_SERVERS\n", re ))
|
||||
return false;
|
||||
QStringList sess = QString(re.data() +3).split( QChar(';'), QString::SkipEmptyParts);
|
||||
for (QStringList::ConstIterator it = sess.begin(); it != sess.end(); ++it) {
|
||||
QStringList ts = (*it).split( QChar(',') );
|
||||
SessEnt se;
|
||||
se.display = ts[0];
|
||||
se.user = ts[1];
|
||||
se.vt = ts[2].toInt();
|
||||
se.session = "<unknown>";
|
||||
se.self = ts[0] == ::getenv( "DISPLAY" ); /* Bleh */
|
||||
se.tty = false;
|
||||
list.append( se );
|
||||
}
|
||||
} else {
|
||||
if (!exec( "list\talllocal\n", re ))
|
||||
return false;
|
||||
QStringList sess = QString(re.data() + 3).split(QChar('\t'), QString::SkipEmptyParts );
|
||||
for (QStringList::ConstIterator it = sess.begin(); it != sess.end(); ++it) {
|
||||
QStringList ts = (*it).split( QChar(',') );
|
||||
SessEnt se;
|
||||
se.display = ts[0];
|
||||
if (ts[1][0] == '@')
|
||||
se.from = ts[1].mid( 1 ), se.vt = 0;
|
||||
else
|
||||
se.vt = ts[1].mid( 2 ).toInt();
|
||||
se.user = ts[2];
|
||||
se.session = ts[3];
|
||||
se.self = (ts[4].indexOf( '*' ) >= 0);
|
||||
se.tty = (ts[4].indexOf( 't' ) >= 0);
|
||||
list.append( se );
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
KDisplayManager::sess2Str2( const SessEnt &se, QString &user, QString &loc )
|
||||
{
|
||||
if (se.tty) {
|
||||
user = i18nc("user: ...", "%1: TTY login", se.user );
|
||||
loc = se.vt ? QString("vt%1").arg( se.vt ) : se.display ;
|
||||
} else {
|
||||
user =
|
||||
se.user.isEmpty() ?
|
||||
se.session.isEmpty() ?
|
||||
i18n("Unused") :
|
||||
se.session == "<remote>" ?
|
||||
i18n("X login on remote host") :
|
||||
i18nc("... host", "X login on %1", se.session ) :
|
||||
se.session == "<unknown>" ?
|
||||
se.user :
|
||||
i18nc("user: session type", "%1: %2",
|
||||
se.user, se.session );
|
||||
loc =
|
||||
se.vt ?
|
||||
QString("%1, vt%2").arg( se.display ).arg( se.vt ) :
|
||||
se.display;
|
||||
}
|
||||
}
|
||||
|
||||
QString
|
||||
KDisplayManager::sess2Str( const SessEnt &se )
|
||||
{
|
||||
QString user, loc;
|
||||
|
||||
sess2Str2( se, user, loc );
|
||||
return i18nc("session (location)", "%1 (%2)", user, loc );
|
||||
}
|
||||
|
||||
bool
|
||||
KDisplayManager::switchVT( int vt )
|
||||
{
|
||||
if (DMType == GDM)
|
||||
return exec( QString("SET_VT %1\n").arg(vt).toLatin1() );
|
||||
|
||||
return exec( QString("activate\tvt%1\n").arg(vt).toLatin1() );
|
||||
}
|
||||
|
||||
void
|
||||
KDisplayManager::lockSwitchVT( int vt )
|
||||
{
|
||||
if (switchVT( vt ))
|
||||
{
|
||||
QDBusInterface screensaver("org.freedesktop.ScreenSaver", "/ScreenSaver", "org.freedesktop.ScreenSaver");
|
||||
screensaver.call( "Lock" );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
KDisplayManager::GDMAuthenticate()
|
||||
{
|
||||
FILE *fp;
|
||||
const char *dpy, *dnum, *dne;
|
||||
int dnl;
|
||||
Xauth *xau;
|
||||
|
||||
dpy = DisplayString( QX11Info::display() );
|
||||
if (!dpy) {
|
||||
dpy = ::getenv( "DISPLAY" );
|
||||
if (!dpy)
|
||||
return;
|
||||
}
|
||||
dnum = strchr( dpy, ':' ) + 1;
|
||||
dne = strchr( dpy, '.' );
|
||||
dnl = dne ? dne - dnum : strlen( dnum );
|
||||
|
||||
/* XXX should do locking */
|
||||
if (!(fp = fopen( XauFileName(), "r" )))
|
||||
return;
|
||||
|
||||
while ((xau = XauReadAuth( fp ))) {
|
||||
if (xau->family == FamilyLocal &&
|
||||
xau->number_length == dnl && !memcmp( xau->number, dnum, dnl ) &&
|
||||
xau->data_length == 16 &&
|
||||
xau->name_length == 18 && !memcmp( xau->name, "MIT-MAGIC-COOKIE-1", 18 ))
|
||||
{
|
||||
QString cmd( "AUTH_LOCAL " );
|
||||
for (int i = 0; i < 16; i++)
|
||||
cmd += QString::number( (uchar)xau->data[i], 16 ).rightJustified( 2, '0');
|
||||
cmd += '\n';
|
||||
if (exec( cmd.toLatin1() )) {
|
||||
XauDisposeAuth( xau );
|
||||
break;
|
||||
}
|
||||
}
|
||||
XauDisposeAuth( xau );
|
||||
}
|
||||
|
||||
fclose (fp);
|
||||
}
|
||||
|
||||
#endif // Q_WS_X11
|
102
kworkspace/kdisplaymanager.h
Normal file
102
kworkspace/kdisplaymanager.h
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
Copyright (C) 2004,2005 Oswald Buddenhagen <ossi@kde.org>
|
||||
Copyright (C) 2005 Stephan Kulow <coolo@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the Lesser 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 Lesser GNU General Public License
|
||||
along with this program; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef KDISPLAYMANAGER_H
|
||||
#define KDISPLAYMANAGER_H
|
||||
|
||||
#include "kworkspace.h"
|
||||
#include <kdemacros.h>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QByteArray>
|
||||
|
||||
struct KDE_EXPORT SessEnt {
|
||||
QString display, from, user, session;
|
||||
int vt;
|
||||
bool self:1, tty:1;
|
||||
};
|
||||
|
||||
typedef QList<SessEnt> SessList;
|
||||
|
||||
class KDE_EXPORT KDisplayManager {
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
|
||||
public:
|
||||
KDisplayManager();
|
||||
~KDisplayManager();
|
||||
|
||||
bool canShutdown();
|
||||
void shutdown( KWorkSpace::ShutdownType shutdownType,
|
||||
KWorkSpace::ShutdownMode shutdownMode,
|
||||
const QString &bootOption = QString() );
|
||||
|
||||
void setLock( bool on );
|
||||
|
||||
bool isSwitchable();
|
||||
int numReserve();
|
||||
void startReserve();
|
||||
bool localSessions( SessList &list );
|
||||
bool switchVT( int vt );
|
||||
void lockSwitchVT( int vt );
|
||||
|
||||
bool bootOptions( QStringList &opts, int &dflt, int &curr );
|
||||
|
||||
static QString sess2Str( const SessEnt &se );
|
||||
static void sess2Str2( const SessEnt &se, QString &user, QString &loc );
|
||||
|
||||
private:
|
||||
bool exec( const char *cmd, QByteArray &ret );
|
||||
bool exec( const char *cmd );
|
||||
|
||||
void GDMAuthenticate();
|
||||
|
||||
#else // Q_WS_X11
|
||||
|
||||
public:
|
||||
KDisplayManager() {}
|
||||
|
||||
bool canShutdown() { return false; }
|
||||
void shutdown( KWorkSpace::ShutdownType shutdownType,
|
||||
KWorkSpace::ShutdownMode shutdownMode,
|
||||
const QString &bootOption = QString() ) {}
|
||||
|
||||
void setLock( bool ) {}
|
||||
|
||||
bool isSwitchable() { return false; }
|
||||
int numReserve() { return -1; }
|
||||
void startReserve() {}
|
||||
bool localSessions( SessList &list ) { return false; }
|
||||
void switchVT( int vt ) {}
|
||||
|
||||
bool bootOptions( QStringList &opts, int &dflt, int &curr );
|
||||
|
||||
#endif // Q_WS_X11
|
||||
|
||||
private:
|
||||
#ifdef Q_WS_X11
|
||||
class Private;
|
||||
Private * const d;
|
||||
#endif // Q_WS_X11
|
||||
|
||||
}; // class KDisplayManager
|
||||
|
||||
#endif // KDISPLAYMANAGER_H
|
||||
|
228
kworkspace/kwindowlistmenu.cpp
Normal file
228
kworkspace/kwindowlistmenu.cpp
Normal file
@ -0,0 +1,228 @@
|
||||
/*****************************************************************
|
||||
|
||||
Copyright (c) 2000 Matthias Elter <elter@kde.org>
|
||||
Matthias Ettrich <ettrich@kde.org>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
******************************************************************/
|
||||
|
||||
#include "kwindowlistmenu.h"
|
||||
|
||||
#include <QtCore/QBool>
|
||||
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QDesktopWidget>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QX11Info>
|
||||
|
||||
#include <QtDBus/QtDBus>
|
||||
#include <klocale.h>
|
||||
#include <kstringhandler.h>
|
||||
#include <kstyle.h>
|
||||
#include <kwindowsystem.h>
|
||||
#include <netwm.h>
|
||||
|
||||
#undef Bool
|
||||
#include "kwindowlistmenu.moc"
|
||||
#include "kwin_interface.h"
|
||||
|
||||
static bool compareKWinWindowInfo( KWindowInfo* firstInfo, KWindowInfo* secondInfo )
|
||||
{
|
||||
QString firstTitle, secondTitle;
|
||||
|
||||
if ( firstInfo )
|
||||
firstTitle = firstInfo->visibleNameWithState().toLower();
|
||||
|
||||
if ( secondInfo )
|
||||
secondTitle = secondInfo->visibleNameWithState().toLower();
|
||||
|
||||
return firstTitle.compare( secondTitle ) >= 0;
|
||||
}
|
||||
|
||||
class KWindowListMenu::Private
|
||||
{
|
||||
};
|
||||
|
||||
KWindowListMenu::KWindowListMenu( QWidget *parent )
|
||||
: KMenu( parent ), d( new Private )
|
||||
{
|
||||
}
|
||||
|
||||
KWindowListMenu::~KWindowListMenu()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
static bool standaloneDialog( const KWindowInfo* info, const QList<KWindowInfo*>& list )
|
||||
{
|
||||
WId group = info->groupLeader();
|
||||
|
||||
if ( group == 0 )
|
||||
return info->transientFor() == QX11Info::appRootWindow();
|
||||
|
||||
foreach ( KWindowInfo* info, list )
|
||||
if ( info->groupLeader() == group )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void KWindowListMenu::init()
|
||||
{
|
||||
int numberOfDesktops = KWindowSystem::numberOfDesktops();
|
||||
int currentDesktop = KWindowSystem::currentDesktop();
|
||||
WId activeWindow = KWindowSystem::activeWindow();
|
||||
|
||||
// Make sure the popup is not too wide, otherwise clicking in the middle of kdesktop
|
||||
// wouldn't leave any place for the popup, and release would activate some menu entry.
|
||||
int maxwidth = qApp->desktop()->screenGeometry( this ).width() / 2 - 100;
|
||||
|
||||
clear();
|
||||
|
||||
QAction* unclutter = addAction( i18n("Unclutter Windows"),
|
||||
this, SLOT( slotUnclutterWindows() ) );
|
||||
QAction* cascade = addAction( i18n("Cascade Windows"),
|
||||
this, SLOT( slotCascadeWindows() ) );
|
||||
|
||||
// if we only have one desktop we won't be showing titles, so put a separator in
|
||||
if ( numberOfDesktops == 1 )
|
||||
addSeparator();
|
||||
|
||||
QList<KWindowInfo> windows;
|
||||
foreach ( WId id, KWindowSystem::windows() )
|
||||
windows.append( KWindowSystem::windowInfo( id, NET::WMDesktop ) );
|
||||
|
||||
bool showAllDesktopsGroup = ( numberOfDesktops > 1 );
|
||||
|
||||
int i = 0;
|
||||
for ( int j = 1; j <= numberOfDesktops + (showAllDesktopsGroup ? 1 : 0); j++ ) {
|
||||
bool onAllDesktops = ( j > numberOfDesktops );
|
||||
int items = 0;
|
||||
|
||||
// KDE4 porting - huh? didn't know you could set an item checked before it's created?
|
||||
//if (!activeWindow && d == cd)
|
||||
//setItemChecked(1000 + d, true);
|
||||
|
||||
QList<KWindowInfo*> list;
|
||||
|
||||
foreach (const KWindowInfo &wi, windows) {
|
||||
if ( (wi.desktop() == j) || (onAllDesktops && wi.onAllDesktops())
|
||||
|| (!showAllDesktopsGroup && wi.onAllDesktops()) ) {
|
||||
list.append( new KWindowInfo( wi.win(),
|
||||
NET::WMVisibleName | NET::WMState | NET::XAWMState | NET::WMWindowType,
|
||||
NET::WM2GroupLeader | NET::WM2TransientFor ) );
|
||||
}
|
||||
}
|
||||
|
||||
qStableSort( list.begin(), list.end(), compareKWinWindowInfo );
|
||||
|
||||
foreach ( KWindowInfo* info, list ) {
|
||||
++i;
|
||||
QString itemText = fontMetrics().elidedText(info->visibleNameWithState(), Qt::ElideMiddle, maxwidth);
|
||||
|
||||
NET::WindowType windowType = info->windowType( NET::NormalMask | NET::DesktopMask
|
||||
| NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
|
||||
| NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask );
|
||||
|
||||
if ( (windowType == NET::Normal || windowType == NET::Unknown
|
||||
|| (windowType == NET::Dialog && standaloneDialog( info, list )))
|
||||
&& !(info->state() & NET::SkipTaskbar) ) {
|
||||
|
||||
QPixmap pm = KWindowSystem::icon( info->win(), 16, 16, true );
|
||||
items++;
|
||||
|
||||
// ok, we have items on this desktop, let's show the title
|
||||
if ( items == 1 && numberOfDesktops > 1 ) {
|
||||
if( !onAllDesktops )
|
||||
addTitle( KWindowSystem::desktopName( j ) );
|
||||
else
|
||||
addTitle( i18n( "On All Desktops" ) );
|
||||
}
|
||||
|
||||
// Avoid creating unwanted accelerators.
|
||||
itemText.replace( '&', QLatin1String( "&&" ));
|
||||
|
||||
QAction* action = addAction( pm, itemText, this, SLOT( slotForceActiveWindow() ) );
|
||||
action->setData( (int)info->win() );
|
||||
|
||||
if ( info->win() == activeWindow )
|
||||
action->setChecked( true );
|
||||
}
|
||||
}
|
||||
|
||||
if ( j == currentDesktop ) {
|
||||
unclutter->setEnabled( items > 0 );
|
||||
cascade->setEnabled( items > 0 );
|
||||
}
|
||||
|
||||
qDeleteAll( list );
|
||||
}
|
||||
|
||||
// no windows?
|
||||
if ( i == 0 ) {
|
||||
if ( numberOfDesktops > 1 )
|
||||
addSeparator(); // because we don't have any titles, nor a separator
|
||||
|
||||
addAction( i18n( "No Windows" ) )->setEnabled( false );
|
||||
}
|
||||
}
|
||||
|
||||
void KWindowListMenu::slotForceActiveWindow()
|
||||
{
|
||||
QAction* window = qobject_cast<QAction*>(sender());
|
||||
if (!window || !window->data().canConvert(QVariant::Int))
|
||||
return;
|
||||
|
||||
KWindowSystem::forceActiveWindow(window->data().toInt());
|
||||
}
|
||||
|
||||
void KWindowListMenu::slotSetCurrentDesktop()
|
||||
{
|
||||
QAction* window = qobject_cast<QAction*>(sender());
|
||||
if (!window || !window->data().canConvert(QVariant::Int))
|
||||
return;
|
||||
|
||||
KWindowSystem::setCurrentDesktop(window->data().toInt());
|
||||
}
|
||||
|
||||
// This popup is much more useful from keyboard if it has the active
|
||||
// window active by default - however, QPopupMenu tries hard to resist.
|
||||
// QPopupMenu::popup() resets the active item, so this needs to be
|
||||
// called after popup().
|
||||
void KWindowListMenu::selectActiveWindow()
|
||||
{
|
||||
foreach (QAction* action, actions())
|
||||
if (action->isChecked()) {
|
||||
setActiveAction(action);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void KWindowListMenu::slotUnclutterWindows()
|
||||
{
|
||||
org::kde::KWin kwin("org.kde.kwin", "/KWin", QDBusConnection::sessionBus());
|
||||
kwin.unclutterDesktop();
|
||||
}
|
||||
|
||||
void KWindowListMenu::slotCascadeWindows()
|
||||
{
|
||||
org::kde::KWin kwin("org.kde.kwin", "/KWin", QDBusConnection::sessionBus());
|
||||
kwin.cascadeDesktop();
|
||||
}
|
||||
|
79
kworkspace/kwindowlistmenu.h
Normal file
79
kworkspace/kwindowlistmenu.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*****************************************************************
|
||||
|
||||
Copyright (c) 2000 Matthias Elter <elter@kde.org>
|
||||
Matthias Ettrich <ettrich@kde.org>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
******************************************************************/
|
||||
|
||||
#ifndef KWINDOWLISTMENU_H
|
||||
#define KWINDOWLISTMENU_H
|
||||
|
||||
#include <kdemacros.h>
|
||||
#include <kmenu.h>
|
||||
|
||||
/**
|
||||
* This class provides a menu which contains actions
|
||||
* to manage a window. It is used by the window manager
|
||||
* for example an accessable there via the menu button of
|
||||
* the window decoration.
|
||||
*/
|
||||
class KDE_EXPORT KWindowListMenu : public KMenu
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a new window list menu.
|
||||
*
|
||||
* @param parent The parent widget.
|
||||
*/
|
||||
explicit KWindowListMenu( QWidget *parent = 0 );
|
||||
|
||||
/**
|
||||
* Destroys the window list menu.
|
||||
*/
|
||||
virtual ~KWindowListMenu();
|
||||
|
||||
/**
|
||||
* Initializes the menu by filling it with actions
|
||||
* for managing a window.
|
||||
*/
|
||||
void init();
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* Pre-selects the active window in the popup menu, for faster
|
||||
* keyboard navigation. Needs to be called after popup().
|
||||
* Should not be used when the popup is invoked using the mouse.
|
||||
*/
|
||||
void selectActiveWindow();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void slotForceActiveWindow();
|
||||
void slotSetCurrentDesktop();
|
||||
void slotUnclutterWindows();
|
||||
void slotCascadeWindows();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private* const d;
|
||||
};
|
||||
|
||||
#endif
|
236
kworkspace/kworkspace.cpp
Normal file
236
kworkspace/kworkspace.cpp
Normal file
@ -0,0 +1,236 @@
|
||||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
|
||||
|
||||
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 "kworkspace.h"
|
||||
#include <QApplication>
|
||||
#include <QDataStream>
|
||||
#include <kapplication.h>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QTextStream>
|
||||
#include <klocale.h>
|
||||
#include <QDateTime>
|
||||
#include <kstandarddirs.h>
|
||||
#include <QtDBus/QtDBus>
|
||||
#include <stdlib.h> // getenv()
|
||||
#include <ksmserver_interface.h>
|
||||
#include <kdefakes.h>
|
||||
#include <QSocketNotifier>
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/SM/SMlib.h>
|
||||
#include <fixx11h.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
#define DISPLAY "DISPLAY"
|
||||
#elif defined(Q_WS_QWS)
|
||||
#define DISPLAY "QWS_DISPLAY"
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "kworkspace_p.h"
|
||||
|
||||
namespace KWorkSpace
|
||||
{
|
||||
|
||||
static void save_yourself_callback( SmcConn conn_P, SmPointer, int, Bool , int, Bool )
|
||||
{
|
||||
SmcSaveYourselfDone( conn_P, True );
|
||||
}
|
||||
|
||||
static void dummy_callback( SmcConn, SmPointer )
|
||||
{
|
||||
}
|
||||
|
||||
KRequestShutdownHelper::KRequestShutdownHelper()
|
||||
{
|
||||
SmcCallbacks calls;
|
||||
calls.save_yourself.callback = save_yourself_callback;
|
||||
calls.die.callback = dummy_callback;
|
||||
calls.save_complete.callback = dummy_callback;
|
||||
calls.shutdown_cancelled.callback = dummy_callback;
|
||||
char* id = NULL;
|
||||
char err[ 11 ];
|
||||
conn = SmcOpenConnection( NULL, NULL, 1, 0,
|
||||
SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask
|
||||
| SmcShutdownCancelledProcMask, &calls, NULL, &id, 10, err );
|
||||
if( id != NULL )
|
||||
free( id );
|
||||
if( conn == NULL )
|
||||
return; // no SM
|
||||
// set the required properties, mostly dummy values
|
||||
SmPropValue propvalue[ 5 ];
|
||||
SmProp props[ 5 ];
|
||||
propvalue[ 0 ].length = sizeof( int );
|
||||
int value0 = SmRestartNever; // so that this extra SM connection doesn't interfere
|
||||
propvalue[ 0 ].value = &value0;
|
||||
props[ 0 ].name = const_cast< char* >( SmRestartStyleHint );
|
||||
props[ 0 ].type = const_cast< char* >( SmCARD8 );
|
||||
props[ 0 ].num_vals = 1;
|
||||
props[ 0 ].vals = &propvalue[ 0 ];
|
||||
struct passwd* entry = getpwuid( geteuid() );
|
||||
propvalue[ 1 ].length = entry != NULL ? strlen( entry->pw_name ) : 0;
|
||||
propvalue[ 1 ].value = (SmPointer)( entry != NULL ? entry->pw_name : "" );
|
||||
props[ 1 ].name = const_cast< char* >( SmUserID );
|
||||
props[ 1 ].type = const_cast< char* >( SmARRAY8 );
|
||||
props[ 1 ].num_vals = 1;
|
||||
props[ 1 ].vals = &propvalue[ 1 ];
|
||||
propvalue[ 2 ].length = 0;
|
||||
propvalue[ 2 ].value = (SmPointer)( "" );
|
||||
props[ 2 ].name = const_cast< char* >( SmRestartCommand );
|
||||
props[ 2 ].type = const_cast< char* >( SmLISTofARRAY8 );
|
||||
props[ 2 ].num_vals = 1;
|
||||
props[ 2 ].vals = &propvalue[ 2 ];
|
||||
propvalue[ 3 ].length = strlen( "requestshutdownhelper" );
|
||||
propvalue[ 3 ].value = (SmPointer)"requestshutdownhelper";
|
||||
props[ 3 ].name = const_cast< char* >( SmProgram );
|
||||
props[ 3 ].type = const_cast< char* >( SmARRAY8 );
|
||||
props[ 3 ].num_vals = 1;
|
||||
props[ 3 ].vals = &propvalue[ 3 ];
|
||||
propvalue[ 4 ].length = 0;
|
||||
propvalue[ 4 ].value = (SmPointer)( "" );
|
||||
props[ 4 ].name = const_cast< char* >( SmCloneCommand );
|
||||
props[ 4 ].type = const_cast< char* >( SmLISTofARRAY8 );
|
||||
props[ 4 ].num_vals = 1;
|
||||
props[ 4 ].vals = &propvalue[ 4 ];
|
||||
SmProp* p[ 5 ] = { &props[ 0 ], &props[ 1 ], &props[ 2 ], &props[ 3 ], &props[ 4 ] };
|
||||
SmcSetProperties( conn, 5, p );
|
||||
notifier = new QSocketNotifier( IceConnectionNumber( SmcGetIceConnection( conn )),
|
||||
QSocketNotifier::Read, this );
|
||||
connect( notifier, SIGNAL( activated( int )), SLOT( processData()));
|
||||
}
|
||||
|
||||
KRequestShutdownHelper::~KRequestShutdownHelper()
|
||||
{
|
||||
if( conn != NULL )
|
||||
{
|
||||
delete notifier;
|
||||
SmcCloseConnection( conn, 0, NULL );
|
||||
}
|
||||
}
|
||||
|
||||
void KRequestShutdownHelper::processData()
|
||||
{
|
||||
if( conn != NULL )
|
||||
IceProcessMessages( SmcGetIceConnection( conn ), 0, 0 );
|
||||
}
|
||||
|
||||
bool KRequestShutdownHelper::requestShutdown( ShutdownConfirm confirm )
|
||||
{
|
||||
if( conn == NULL )
|
||||
return false;
|
||||
SmcRequestSaveYourself( conn, SmSaveBoth, True, SmInteractStyleAny,
|
||||
confirm == ShutdownConfirmNo, True );
|
||||
// flush the request
|
||||
IceFlush(SmcGetIceConnection(conn));
|
||||
return true;
|
||||
}
|
||||
|
||||
static KRequestShutdownHelper* helper = NULL;
|
||||
|
||||
static void cleanup_sm()
|
||||
{
|
||||
delete helper;
|
||||
}
|
||||
|
||||
bool requestShutDown(
|
||||
ShutdownConfirm confirm, ShutdownType sdtype, ShutdownMode sdmode )
|
||||
{
|
||||
QApplication::syncX();
|
||||
kapp->updateRemoteUserTimestamp( "org.kde.ksmserver" );
|
||||
/* use ksmserver's dcop interface if necessary */
|
||||
if ( confirm == ShutdownConfirmYes ||
|
||||
sdtype != ShutdownTypeDefault ||
|
||||
sdmode != ShutdownModeDefault )
|
||||
{
|
||||
org::kde::KSMServerInterface ksmserver("org.kde.ksmserver", "/KSMServer", QDBusConnection::sessionBus());
|
||||
QDBusReply<void> reply = ksmserver.logout((int)confirm, (int)sdtype, (int)sdmode);
|
||||
return (reply.isValid());
|
||||
}
|
||||
if( helper == NULL )
|
||||
{
|
||||
helper = new KRequestShutdownHelper();
|
||||
qAddPostRoutine(cleanup_sm);
|
||||
}
|
||||
return helper->requestShutdown( confirm );
|
||||
}
|
||||
|
||||
bool canShutDown( ShutdownConfirm confirm,
|
||||
ShutdownType sdtype,
|
||||
ShutdownMode sdmode )
|
||||
{
|
||||
if ( confirm == ShutdownConfirmYes ||
|
||||
sdtype != ShutdownTypeDefault ||
|
||||
sdmode != ShutdownModeDefault )
|
||||
{
|
||||
org::kde::KSMServerInterface ksmserver("org.kde.ksmserver", "/KSMServer", QDBusConnection::sessionBus());
|
||||
QDBusReply<bool> reply = ksmserver.canShutdown();
|
||||
if (!reply.isValid()) {
|
||||
return false;
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static QTime smModificationTime;
|
||||
void propagateSessionManager()
|
||||
{
|
||||
QByteArray fName = QFile::encodeName(KStandardDirs::locateLocal("socket", "KSMserver"));
|
||||
QString display = QString::fromLocal8Bit( ::getenv(DISPLAY) );
|
||||
// strip the screen number from the display
|
||||
display.remove(QRegExp("\\.[0-9]+$"));
|
||||
int i;
|
||||
while( (i = display.indexOf(':')) >= 0)
|
||||
display[i] = '_';
|
||||
|
||||
fName += '_';
|
||||
fName += display.toLocal8Bit();
|
||||
QByteArray smEnv = ::getenv("SESSION_MANAGER");
|
||||
bool check = smEnv.isEmpty();
|
||||
if ( !check && smModificationTime.isValid() ) {
|
||||
QFileInfo info( fName );
|
||||
QTime current = info.lastModified().time();
|
||||
check = current > smModificationTime;
|
||||
}
|
||||
if ( check ) {
|
||||
QFile f( fName );
|
||||
if ( !f.open( QIODevice::ReadOnly ) )
|
||||
return;
|
||||
QFileInfo info ( f );
|
||||
smModificationTime = QTime( info.lastModified().time() );
|
||||
QTextStream t(&f);
|
||||
t.setCodec( "ISO 8859-1" );
|
||||
QString s = t.readLine();
|
||||
f.close();
|
||||
::setenv( "SESSION_MANAGER", s.toLatin1(), true );
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
#include "kworkspace_p.moc"
|
150
kworkspace/kworkspace.h
Normal file
150
kworkspace/kworkspace.h
Normal file
@ -0,0 +1,150 @@
|
||||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
|
||||
|
||||
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 KWORKSPACE_H
|
||||
#define KWORKSPACE_H
|
||||
|
||||
#include <kdemacros.h>
|
||||
|
||||
namespace KWorkSpace
|
||||
{
|
||||
|
||||
/**
|
||||
* The possible values for the @p confirm parameter of requestShutDown().
|
||||
*/
|
||||
enum ShutdownConfirm {
|
||||
/**
|
||||
* Obey the user's confirmation setting.
|
||||
*/
|
||||
ShutdownConfirmDefault = -1,
|
||||
/**
|
||||
* Don't confirm, shutdown without asking.
|
||||
*/
|
||||
ShutdownConfirmNo = 0,
|
||||
/**
|
||||
* Always confirm, ask even if the user turned it off.
|
||||
*/
|
||||
ShutdownConfirmYes = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* The possible values for the @p sdtype parameter of requestShutDown().
|
||||
*/
|
||||
enum ShutdownType {
|
||||
/**
|
||||
* Select previous action or the default if it's the first time.
|
||||
*/
|
||||
ShutdownTypeDefault = -1,
|
||||
/**
|
||||
* Only show log out dialog
|
||||
*/
|
||||
ShutdownTypeNone = 0,
|
||||
/**
|
||||
* Log out and reboot the machine.
|
||||
*/
|
||||
ShutdownTypeReboot = 1,
|
||||
/**
|
||||
* Log out and halt the machine.
|
||||
*/
|
||||
ShutdownTypeHalt = 2,
|
||||
/**
|
||||
* Only log out
|
||||
*/
|
||||
ShutdownTypeLogout = 3
|
||||
};
|
||||
|
||||
/**
|
||||
* The possible values for the @p sdmode parameter of requestShutDown().
|
||||
*/
|
||||
enum ShutdownMode {
|
||||
/**
|
||||
* Select previous mode or the default if it's the first time.
|
||||
*/
|
||||
ShutdownModeDefault = -1,
|
||||
/**
|
||||
* Schedule a shutdown (halt or reboot) for the time all active sessions
|
||||
* have exited.
|
||||
*/
|
||||
ShutdownModeSchedule = 0,
|
||||
/**
|
||||
* Shut down, if no sessions are active. Otherwise do nothing.
|
||||
*/
|
||||
ShutdownModeTryNow = 1,
|
||||
/**
|
||||
* Force shutdown. Kill any possibly active sessions.
|
||||
*/
|
||||
ShutdownModeForceNow = 2,
|
||||
/**
|
||||
* Pop up a dialog asking the user what to do if sessions are still active.
|
||||
*/
|
||||
ShutdownModeInteractive = 3
|
||||
};
|
||||
|
||||
/**
|
||||
* Asks the session manager to shut the session down.
|
||||
*
|
||||
* Using @p confirm == ShutdownConfirmYes or @p sdtype != ShutdownTypeDefault or
|
||||
* @p sdmode != ShutdownModeDefault causes the use of ksmserver's DCOP
|
||||
* interface. The remaining two combinations use the standard XSMP and
|
||||
* will work with any session manager compliant with it.
|
||||
*
|
||||
* @param confirm Whether to ask the user if he really wants to log out.
|
||||
* ShutdownConfirm
|
||||
* @param sdtype The action to take after logging out. ShutdownType
|
||||
* @param sdmode If/When the action should be taken. ShutdownMode
|
||||
* @return true on success, false if the session manager could not be
|
||||
* contacted.
|
||||
*/
|
||||
KDE_EXPORT bool requestShutDown( ShutdownConfirm confirm = ShutdownConfirmDefault,
|
||||
ShutdownType sdtype = ShutdownTypeDefault,
|
||||
ShutdownMode sdmode = ShutdownModeDefault );
|
||||
|
||||
/**
|
||||
* Used to check whether a requestShutDown call with the same arguments
|
||||
* has any chance of succeeding.
|
||||
*
|
||||
* For example, if KDE's own session manager cannot be contacted, we can't
|
||||
* demand that the computer be shutdown, or force a confirmation dialog.
|
||||
*
|
||||
* Even if we can access the KDE session manager, the system or user
|
||||
* configuration may prevent the user from requesting a shutdown or
|
||||
* reboot.
|
||||
*/
|
||||
KDE_EXPORT bool canShutDown( ShutdownConfirm confirm = ShutdownConfirmDefault,
|
||||
ShutdownType sdtype = ShutdownTypeDefault,
|
||||
ShutdownMode sdmode = ShutdownModeDefault );
|
||||
|
||||
/**
|
||||
* Propagates the network address of the session manager in the
|
||||
* SESSION_MANAGER environment variable so that child processes can
|
||||
* pick it up.
|
||||
*
|
||||
* If SESSION_MANAGER isn't defined yet, the address is searched in
|
||||
* $HOME/.KSMserver.
|
||||
*
|
||||
* This function is called by clients that are started outside the
|
||||
* session ( i.e. before ksmserver is started), but want to launch
|
||||
* other processes that should participate in the session. Examples
|
||||
* are kdesktop or kicker.
|
||||
*/
|
||||
KDE_EXPORT void propagateSessionManager();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
49
kworkspace/kworkspace_p.h
Normal file
49
kworkspace/kworkspace_p.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org>
|
||||
|
||||
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 KWORKSPACE_P_H
|
||||
#define KWORKSPACE_P_H
|
||||
|
||||
#include "kworkspace.h"
|
||||
|
||||
class QSocketNotifier;
|
||||
|
||||
namespace KWorkSpace
|
||||
{
|
||||
|
||||
// A class that creates another connection to ksmserver and handles it properly.
|
||||
class KRequestShutdownHelper
|
||||
: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
KRequestShutdownHelper();
|
||||
virtual ~KRequestShutdownHelper();
|
||||
bool requestShutdown( ShutdownConfirm confirm );
|
||||
private slots:
|
||||
void processData();
|
||||
private:
|
||||
SmcConn connection() const { return conn; }
|
||||
QSocketNotifier* notifier;
|
||||
SmcConn conn;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
23
libplasmaclock/CMakeLists.txt
Normal file
23
libplasmaclock/CMakeLists.txt
Normal file
@ -0,0 +1,23 @@
|
||||
project(libplasmaclock)
|
||||
|
||||
set(plasmaclock_LIB_SRCS
|
||||
clocknumber.cpp
|
||||
clockapplet.cpp
|
||||
calendar.cpp
|
||||
calendartable.cpp
|
||||
toolbutton.cpp
|
||||
)
|
||||
|
||||
kde4_add_ui_files(plasmaclock_LIB_SRCS calendar.ui timezonesConfig.ui)
|
||||
|
||||
kde4_add_library(plasmaclock SHARED ${plasmaclock_LIB_SRCS})
|
||||
|
||||
target_link_libraries(plasmaclock plasma ${KDE4_KDEUI_LIBS})
|
||||
|
||||
set_target_properties(plasmaclock PROPERTIES VERSION ${GENERIC_LIB_VERSION}
|
||||
SOVERSION ${GENERIC_LIB_SOVERSION} )
|
||||
|
||||
#clockapplet.h
|
||||
install(FILES clocknumber.h clockapplet.h calendar.h calendartable.h plasmaclock_export.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/ui_calendar.h DESTINATION ${INCLUDE_INSTALL_DIR}/libplasmaclock COMPONENT Devel)
|
||||
install(TARGETS plasmaclock ${INSTALL_TARGETS_DEFAULT_ARGS} )
|
2
libplasmaclock/Messages.sh
Executable file
2
libplasmaclock/Messages.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#! /usr/bin/env bash
|
||||
$XGETTEXT *.cpp -o $podir/libplasmaclock.pot
|
206
libplasmaclock/calendar.cpp
Normal file
206
libplasmaclock/calendar.cpp
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2008 Davide Bettio <davide.bettio@kdemail.net>
|
||||
*
|
||||
* This program 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, 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 Library 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 "calendar.h"
|
||||
|
||||
//Qt
|
||||
#include <QtCore/QDate>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtGui/QGraphicsSceneWheelEvent>
|
||||
#include <QtGui/QGraphicsLinearLayout>
|
||||
#include <QtGui/QGraphicsProxyWidget>
|
||||
|
||||
//KDECore
|
||||
#include <kglobal.h>
|
||||
#include <kdebug.h>
|
||||
|
||||
//Plasma
|
||||
#include <plasma/svg.h>
|
||||
#include <plasma/theme.h>
|
||||
#include <plasma/widgets/label.h>
|
||||
|
||||
#include "toolbutton.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class CalendarPrivate
|
||||
{
|
||||
public:
|
||||
ToolButton *back;
|
||||
Plasma::Label *spacer0;
|
||||
Plasma::Label *month;
|
||||
#ifdef COOL_SPINBOX
|
||||
SpinBox *year;
|
||||
#else
|
||||
Plasma::Label *year;
|
||||
#endif
|
||||
Plasma::Label *spacer1;
|
||||
ToolButton *forward;
|
||||
Plasma::CalendarTable *calendarTable;
|
||||
};
|
||||
|
||||
//TODO
|
||||
Calendar::Calendar(const QDate &, QGraphicsWidget *parent)
|
||||
: QGraphicsWidget(parent), d(new CalendarPrivate())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Calendar::Calendar(QGraphicsWidget *parent)
|
||||
: QGraphicsWidget(parent), d(new CalendarPrivate())
|
||||
{
|
||||
QGraphicsLinearLayout *m_layout = new QGraphicsLinearLayout(Qt::Vertical, this);
|
||||
QGraphicsLinearLayout *m_hLayout = new QGraphicsLinearLayout(m_layout);
|
||||
|
||||
d->calendarTable = new Plasma::CalendarTable(this);
|
||||
d->calendarTable->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
connect(d->calendarTable, SIGNAL(displayedMonthChanged(int, int)), this, SLOT(displayedMonthChanged(int, int)));
|
||||
|
||||
QGraphicsProxyWidget *backProxy = new QGraphicsProxyWidget(this);
|
||||
d->back = new ToolButton();
|
||||
d->back->setText("<");
|
||||
d->back->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
connect(d->back, SIGNAL(clicked()), this, SLOT(prevMonth()));
|
||||
backProxy->setWidget(d->back);
|
||||
m_hLayout->addItem(backProxy);
|
||||
|
||||
d->spacer0 = new Plasma::Label(this);
|
||||
d->spacer0->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
m_hLayout->addItem(d->spacer0);
|
||||
|
||||
d->month = new Plasma::Label(this);
|
||||
d->month->setText(d->calendarTable->calendar()->monthName(d->calendarTable->calendar()->month(d->calendarTable->date()), d->calendarTable->calendar()->year(d->calendarTable->date())));
|
||||
d->month->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
m_hLayout->addItem(d->month);
|
||||
|
||||
#ifdef COOL_SPINBOX
|
||||
QGraphicsProxyWidget *yearProxy = new QGraphicsProxyWidget(this);
|
||||
d->year = new SpinBox();
|
||||
d->year->setRange(d->calendarTable->calendar()->year(d->calendarTable->calendar()->earliestValidDate()), d->calendarTable->calendar()->year(d->calendarTable->calendar()->latestValidDate()));
|
||||
d->year->setValue(d->calendarTable->calendar()->year(d->calendarTable->date()));
|
||||
yearProxy->setWidget(d->year);
|
||||
m_hLayout->addItem(yearProxy);
|
||||
#else
|
||||
d->year = new Plasma::Label;
|
||||
d->year->setText(QString::number(d->calendarTable->calendar()->year(d->calendarTable->date())));
|
||||
d->year->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
m_hLayout->addItem(d->year);
|
||||
#endif
|
||||
|
||||
d->spacer1 = new Plasma::Label(this);
|
||||
d->spacer1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
m_hLayout->addItem(d->spacer1);
|
||||
|
||||
QGraphicsProxyWidget *forwardProxy = new QGraphicsProxyWidget(this);
|
||||
d->forward = new ToolButton();
|
||||
d->forward->setText(">");
|
||||
d->forward->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
connect(d->forward, SIGNAL(clicked()), this, SLOT(nextMonth()));
|
||||
forwardProxy->setWidget(d->forward);
|
||||
m_hLayout->addItem(forwardProxy);
|
||||
|
||||
m_layout->addItem(m_hLayout);
|
||||
|
||||
m_layout->addItem(d->calendarTable);
|
||||
}
|
||||
|
||||
Calendar::~Calendar()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool Calendar::setCalendar(KCalendarSystem *calendar)
|
||||
{
|
||||
return d->calendarTable->setCalendar(calendar);
|
||||
}
|
||||
|
||||
bool Calendar::setDate(const QDate &date)
|
||||
{
|
||||
return d->calendarTable->setDate(date);
|
||||
}
|
||||
|
||||
const QDate& Calendar::date() const
|
||||
{
|
||||
return d->calendarTable->date();
|
||||
}
|
||||
|
||||
void Calendar::displayedMonthChanged(int calendarSystemYear, int calendarSystemMonth)
|
||||
{
|
||||
d->month->setText(d->calendarTable->calendar()->monthName(calendarSystemMonth, calendarSystemYear));
|
||||
|
||||
#ifdef COOL_SPINBOX
|
||||
d->year->setValue(calendarSystemYear);
|
||||
#else
|
||||
d->year->setText(QString::number(calendarSystemYear));
|
||||
#endif
|
||||
}
|
||||
|
||||
void Calendar::prevMonth()
|
||||
{
|
||||
QDate tmpDate = d->calendarTable->date();
|
||||
QDate newDate;
|
||||
|
||||
int month = d->calendarTable->calendar()->month(tmpDate);
|
||||
int year = d->calendarTable->calendar()->year(tmpDate);
|
||||
|
||||
if (month == 1){
|
||||
month = 12;
|
||||
year--;
|
||||
}else{
|
||||
month--;
|
||||
}
|
||||
|
||||
if (d->calendarTable->calendar()->setYMD(newDate, year, month, d->calendarTable->calendar()->day(tmpDate))){
|
||||
d->calendarTable->setDate(newDate);
|
||||
}else if (d->calendarTable->calendar()->setYMD(newDate, year, month, 1)){
|
||||
d->calendarTable->setDate(newDate);
|
||||
}
|
||||
}
|
||||
|
||||
void Calendar::nextMonth()
|
||||
{
|
||||
QDate tmpDate = d->calendarTable->date();
|
||||
QDate newDate;
|
||||
|
||||
int month = d->calendarTable->calendar()->month(tmpDate);
|
||||
int year = d->calendarTable->calendar()->year(tmpDate);
|
||||
|
||||
if (month == 12){
|
||||
month = 1;
|
||||
year++;
|
||||
}else{
|
||||
month++;
|
||||
}
|
||||
|
||||
if (d->calendarTable->calendar()->setYMD(newDate, year, month, d->calendarTable->calendar()->day(tmpDate))){
|
||||
d->calendarTable->setDate(newDate);
|
||||
}else if (d->calendarTable->calendar()->setYMD(newDate, year, month, 1)){
|
||||
d->calendarTable->setDate(newDate);
|
||||
}
|
||||
}
|
||||
|
||||
CalendarTable *Calendar::calendarTable() const
|
||||
{
|
||||
return d->calendarTable;
|
||||
}
|
||||
}
|
||||
|
||||
#include "calendar.moc"
|
71
libplasmaclock/calendar.h
Normal file
71
libplasmaclock/calendar.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2008 Davide Bettio <davide.bettio@kdemail.net>
|
||||
*
|
||||
* This program 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, 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 Library 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 PLASMA_CALENDAR_H
|
||||
#define PLASMA_CALENDAR_H
|
||||
|
||||
#include <QtGui/QGraphicsWidget>
|
||||
|
||||
#include "plasmaclock_export.h"
|
||||
|
||||
#include <kcalendarsystem.h>
|
||||
|
||||
#include "calendartable.h"
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class CalendarTable;
|
||||
class CalendarPrivate;
|
||||
|
||||
class PLASMACLOCK_EXPORT Calendar : public QGraphicsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Calendar(QGraphicsWidget *parent = 0);
|
||||
Calendar(const QDate &, QGraphicsWidget *parent = 0);
|
||||
~Calendar();
|
||||
|
||||
const KCalendarSystem *calendar () const;
|
||||
|
||||
bool setDate(const QDate &date);
|
||||
const QDate& date() const;
|
||||
|
||||
bool setCalendar(KCalendarSystem *calendar = 0);
|
||||
|
||||
CalendarTable *calendarTable() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void dateChanged(const QDate &cur, const QDate &old);
|
||||
void dateChanged(const QDate &date);
|
||||
void tableClicked();
|
||||
|
||||
private Q_SLOTS:
|
||||
void displayedMonthChanged(int calendarSystemYear, int calendarSystemMonth);
|
||||
void prevMonth();
|
||||
void nextMonth();
|
||||
|
||||
private:
|
||||
CalendarPrivate* const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
42
libplasmaclock/calendar.ui
Normal file
42
libplasmaclock/calendar.ui
Normal file
@ -0,0 +1,42 @@
|
||||
<ui version="4.0" >
|
||||
<class>calendar</class>
|
||||
<widget class="QWidget" name="calendar" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>276</width>
|
||||
<height>255</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet" >
|
||||
<string notr="true" />
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<property name="spacing" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="KDatePicker" name="kdatepicker" >
|
||||
<property name="autoFillBackground" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KDatePicker</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>kdatepicker.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="resource.qrc" />
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
533
libplasmaclock/calendartable.cpp
Normal file
533
libplasmaclock/calendartable.cpp
Normal file
@ -0,0 +1,533 @@
|
||||
/*
|
||||
* Copyright 2008 Davide Bettio <davide.bettio@kdemail.net>
|
||||
*
|
||||
* This program 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, 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 Library 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 "calendartable.h"
|
||||
|
||||
//Qt
|
||||
#include <QtCore/QDate>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtGui/QGraphicsSceneWheelEvent>
|
||||
#include <QtGui/QStyleOptionGraphicsItem>
|
||||
|
||||
//KDECore
|
||||
#include <kglobal.h>
|
||||
#include <kdebug.h>
|
||||
|
||||
//Plasma
|
||||
#include <plasma/svg.h>
|
||||
#include <plasma/theme.h>
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class CalendarCellBorder
|
||||
{
|
||||
public:
|
||||
CalendarCellBorder(int c, int w, int d, CalendarTable::CellTypes t, QDate dt)
|
||||
: cell(c),
|
||||
week(w),
|
||||
weekDay(d),
|
||||
type(t),
|
||||
date(dt)
|
||||
{
|
||||
}
|
||||
|
||||
int cell;
|
||||
int week;
|
||||
int weekDay;
|
||||
CalendarTable::CellTypes type;
|
||||
QDate date;
|
||||
};
|
||||
|
||||
class CalendarTablePrivate
|
||||
{
|
||||
public:
|
||||
CalendarTablePrivate(CalendarTable *q, const QDate &cDate = QDate::currentDate())
|
||||
{
|
||||
svg = new Svg();
|
||||
svg->setImagePath("widgets/calendar");
|
||||
svg->setContainsMultipleImages(true);
|
||||
|
||||
calendar = KGlobal::locale()->calendar();
|
||||
|
||||
date = cDate;
|
||||
|
||||
QDate currentDate = QDate::currentDate();
|
||||
month = calendar->month(currentDate);
|
||||
year = calendar->year(currentDate);
|
||||
|
||||
setupThemedElements();
|
||||
QObject::connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()),
|
||||
q, SLOT(setupThemedElements()));
|
||||
}
|
||||
|
||||
~CalendarTablePrivate()
|
||||
{
|
||||
delete svg;
|
||||
}
|
||||
|
||||
void setupThemedElements()
|
||||
{
|
||||
QColor c = Plasma::Theme::defaultTheme()->color(Plasma::Theme::HighlightColor);
|
||||
c.setAlpha(180);
|
||||
highlightBrush = QBrush(c);
|
||||
}
|
||||
|
||||
int firstMonthDayIndex(int y, int m)
|
||||
{
|
||||
QDate myDate;
|
||||
calendar->setYMD(myDate, y, m, 1);
|
||||
|
||||
return (((calendar->dayOfWeek(myDate) - 1) + (calendar->daysInWeek(date) - (calendar->weekStartDay() - 1))) % calendar->daysInWeek(date)) + 1;
|
||||
}
|
||||
|
||||
QRectF hoveredCellRect(CalendarTable *q, const QPointF &hoverPoint)
|
||||
{
|
||||
hoverDay = -1;
|
||||
hoverWeek = -1;
|
||||
|
||||
if (hoverPoint.isNull()) {
|
||||
return QRectF();
|
||||
}
|
||||
|
||||
if (hoverPoint.x() < centeringSpace + cellW + weekBarSpace) {
|
||||
// skip the weekbar
|
||||
return QRectF();
|
||||
}
|
||||
|
||||
int x = (hoverPoint.x() - centeringSpace) / (cellW + cellSpace);
|
||||
int y = (hoverPoint.y() - headerHeight - headerSpace) / (cellH + cellSpace);
|
||||
|
||||
if (x < 1 || x > 7 || y < 0 || y > 5) {
|
||||
return QRectF();
|
||||
}
|
||||
|
||||
//FIXME: this should be a hint or something somewhere
|
||||
hoverDay = x - 1;
|
||||
hoverWeek = y;
|
||||
//kDebug () << x << y;
|
||||
return QRectF(q->cellX(x - 1) - glowRadius, q->cellY(y) - glowRadius,
|
||||
cellW + glowRadius * 2, cellH + glowRadius * 2);
|
||||
}
|
||||
|
||||
void updateHoveredPainting(CalendarTable *q, const QPointF &hoverPoint)
|
||||
{
|
||||
QRectF newHoverRect = hoveredCellRect(q, hoverPoint);
|
||||
|
||||
// now update what is needed, and only what is needed!
|
||||
if (newHoverRect.isValid() && newHoverRect != hoverRect) {
|
||||
if (hoverRect.isValid()) {
|
||||
q->update(hoverRect);
|
||||
}
|
||||
q->update(newHoverRect);
|
||||
}
|
||||
|
||||
hoverRect = newHoverRect;
|
||||
}
|
||||
|
||||
int cell(int week, int weekDay, CalendarTable::CellTypes *type, QDate &cellDate)
|
||||
{
|
||||
QDate myDate;
|
||||
|
||||
if ((week == 0) && (weekDay < firstMonthDayIndex(year, month))){
|
||||
int prevMonth = (month == 1) ? 12 : month - 1;
|
||||
calendar->setYMD(myDate, year, prevMonth, 1);
|
||||
|
||||
if (type) {
|
||||
(*type) |= CalendarTable::NotInCurrentMonth;
|
||||
}
|
||||
|
||||
calendar->setYMD(cellDate, (prevMonth == 12) ? year - 1 : year, prevMonth, calendar->daysInMonth(myDate) - (firstMonthDayIndex(year, month) - 1 - weekDay));
|
||||
return calendar->daysInMonth(myDate) - (firstMonthDayIndex(year, month) - 1 - weekDay);
|
||||
} else {
|
||||
calendar->setYMD(myDate, year, month, 1);
|
||||
int day = (week * calendar->daysInWeek(date) + weekDay) - firstMonthDayIndex(year, month) + 1;
|
||||
|
||||
if (day <= calendar->daysInMonth(myDate)) {
|
||||
if (type) {
|
||||
(*type) &= ~CalendarTable::NotInCurrentMonth;
|
||||
}
|
||||
|
||||
calendar->setYMD(cellDate, year, month, day);
|
||||
return day;
|
||||
} else {
|
||||
if (type) {
|
||||
(*type) |= CalendarTable::NotInCurrentMonth;
|
||||
}
|
||||
int nextMonth = (month == 12) ? 1 : month + 1;
|
||||
calendar->setYMD(cellDate, (nextMonth == 1) ? year + 1 : year, nextMonth, day - calendar->daysInMonth(myDate));
|
||||
return day - calendar->daysInMonth(myDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Plasma::Svg *svg;
|
||||
const KCalendarSystem *calendar;
|
||||
QBrush highlightBrush;
|
||||
QDate date;
|
||||
QRectF hoverRect;
|
||||
int month;
|
||||
int year;
|
||||
|
||||
int hoverWeek;
|
||||
int hoverDay;
|
||||
int centeringSpace;
|
||||
int cellW;
|
||||
int cellH;
|
||||
int cellSpace;
|
||||
int headerHeight;
|
||||
int headerSpace;
|
||||
int weekBarSpace;
|
||||
int glowRadius;
|
||||
};
|
||||
|
||||
CalendarTable::CalendarTable(const QDate &date, QGraphicsWidget *parent)
|
||||
: QGraphicsWidget(parent), d(new CalendarTablePrivate(this, date))
|
||||
{
|
||||
}
|
||||
|
||||
CalendarTable::CalendarTable(QGraphicsWidget *parent)
|
||||
: QGraphicsWidget(parent), d(new CalendarTablePrivate(this))
|
||||
{
|
||||
setAcceptHoverEvents(true);
|
||||
}
|
||||
|
||||
CalendarTable::~CalendarTable()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
const KCalendarSystem *CalendarTable::calendar() const
|
||||
{
|
||||
return d->calendar;
|
||||
}
|
||||
|
||||
bool CalendarTable::setCalendar(KCalendarSystem *calendar)
|
||||
{
|
||||
d->calendar = calendar;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CalendarTable::setDate(const QDate &date)
|
||||
{
|
||||
int oldYear = d->year;
|
||||
int oldMonth = d->month;
|
||||
QDate oldDate = d->date;
|
||||
d->date = date;
|
||||
d->year = d->calendar->year(date);
|
||||
d->month = d->calendar->month(date);
|
||||
bool fullUpdate = false;
|
||||
|
||||
if (oldYear != d->year){
|
||||
emit displayedYearChanged(d->year, d->month);
|
||||
fullUpdate = true;
|
||||
}
|
||||
|
||||
if (oldMonth != d->month){
|
||||
emit displayedMonthChanged(d->year, d->month);
|
||||
fullUpdate = true;
|
||||
}
|
||||
|
||||
d->updateHoveredPainting(this, QPointF());
|
||||
|
||||
if (fullUpdate) {
|
||||
update();
|
||||
} else {
|
||||
// only update the old and the new areas
|
||||
int offset = d->firstMonthDayIndex(d->year, d->month);
|
||||
int daysInWeek = d->calendar->daysInWeek(d->date);
|
||||
|
||||
int day = d->calendar->day(oldDate);
|
||||
int x = ((offset + day - 1) % daysInWeek);
|
||||
if (x == 0) {
|
||||
x = daysInWeek;
|
||||
}
|
||||
int y = (offset + day - 2) / daysInWeek;
|
||||
update(cellX(x - 1) - d->glowRadius, cellY(y) - d->glowRadius,
|
||||
d->cellW + d->glowRadius * 2, d->cellH + d->glowRadius * 2);
|
||||
|
||||
day = d->calendar->day(date);
|
||||
x = (offset + day - 1) % daysInWeek;
|
||||
if (x == 0) {
|
||||
x = daysInWeek;
|
||||
}
|
||||
y = (offset + day - 2) / daysInWeek;
|
||||
update(cellX(x - 1) - d->glowRadius, cellY(y) - d->glowRadius,
|
||||
d->cellW + d->glowRadius * 2, d->cellH + d->glowRadius * 2);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const QDate& CalendarTable::date() const
|
||||
{
|
||||
return d->date;
|
||||
}
|
||||
|
||||
int CalendarTable::cellX(int weekDay)
|
||||
{
|
||||
return boundingRect().x() + d->centeringSpace +
|
||||
d->weekBarSpace + d->cellW +
|
||||
((d->cellW + d->cellSpace) * (weekDay));
|
||||
}
|
||||
|
||||
int CalendarTable::cellY(int week)
|
||||
{
|
||||
return (int) boundingRect().y() + (d->cellW + d->cellSpace) * (week) + d->headerHeight + d->headerSpace;
|
||||
}
|
||||
|
||||
void CalendarTable::wheelEvent(QGraphicsSceneWheelEvent * event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
if (event->delta() < 0) {
|
||||
if (d->month == 12) {
|
||||
d->month = 1;
|
||||
d->year++;
|
||||
emit displayedYearChanged(d->year, d->month);
|
||||
} else {
|
||||
d->month++;
|
||||
}
|
||||
|
||||
emit displayedMonthChanged(d->year, d->month);
|
||||
} else if (event->delta() > 0) {
|
||||
if (d->month == 1) {
|
||||
d->month = 12;
|
||||
d->year--;
|
||||
emit displayedYearChanged(d->year, d->month);
|
||||
} else {
|
||||
d->month--;
|
||||
}
|
||||
|
||||
emit displayedMonthChanged(d->year, d->month);
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void CalendarTable::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
event->accept();
|
||||
|
||||
if ((event->pos().x() >= cellX(0)) && (event->pos().x() <= cellX(d->calendar->daysInWeek(d->date)) - d->cellSpace) &&
|
||||
(event->pos().y() >= cellY(0)) && (event->pos().y() <= cellY(5) - d->cellSpace)){
|
||||
|
||||
int week = -1;
|
||||
int weekDay = -1;
|
||||
QDate cellDate;
|
||||
|
||||
for (int i = 0; i < d->calendar->daysInWeek(d->date); i++) {
|
||||
if ((event->pos().x() >= cellX(i)) && (event->pos().x() <= cellX(i + 1) - d->cellSpace))
|
||||
weekDay = i;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if ((event->pos().y() >= cellY(i)) && (event->pos().y() <= cellY(i + 1) - d->cellSpace))
|
||||
week = i;
|
||||
}
|
||||
|
||||
if ((week >= 0) && (weekDay >= 0)) {
|
||||
d->hoverDay = -1;
|
||||
d->hoverWeek = -1;
|
||||
QDate tmpDate;
|
||||
QDate oldDate = d->date;
|
||||
d->cell(week, weekDay + 1, 0, tmpDate);
|
||||
|
||||
if (tmpDate == oldDate) {
|
||||
return;
|
||||
}
|
||||
|
||||
setDate(tmpDate);
|
||||
emit dateChanged(tmpDate, oldDate);
|
||||
emit dateChanged(tmpDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CalendarTable::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
mousePressEvent(event);
|
||||
}
|
||||
|
||||
void CalendarTable::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
emit tableClicked();
|
||||
}
|
||||
|
||||
void CalendarTable::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
|
||||
{
|
||||
d->updateHoveredPainting(this, event->pos());
|
||||
}
|
||||
|
||||
void CalendarTable::resizeEvent(QGraphicsSceneResizeEvent * event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
QRectF r = contentsRect();
|
||||
int rectSize = int(qMin(r.width() / 8, r.height() / 6));
|
||||
|
||||
//Using integers to help to keep things aligned to the grid
|
||||
//kDebug() << r.width() << rectSize;
|
||||
d->cellSpace = qMax(1, qMin(4, rectSize / 20));
|
||||
d->headerSpace = d->cellSpace * 2;
|
||||
d->weekBarSpace = d->cellSpace * 2 + 1;
|
||||
d->cellH = rectSize - d->cellSpace;
|
||||
d->cellW = rectSize - d->cellSpace;
|
||||
d->glowRadius = d->cellW * .1;
|
||||
d->headerHeight = (int) (d->cellH / 1.5);
|
||||
d->centeringSpace = qMax(0, int((r.width() - (rectSize * 8) - (d->cellSpace * 7)) / 2));
|
||||
}
|
||||
|
||||
void CalendarTable::paintCell(QPainter *p, int cell, int week, int weekDay, CellTypes type, const QDate &cellDate)
|
||||
{
|
||||
QString cellSuffix = cellSVGSuffix(cell, week, weekDay, type & NotInCurrentMonth, cellDate);
|
||||
d->svg->paint(p, QRectF(cellX(weekDay), cellY(week), d->cellW, d->cellH), cellSuffix);
|
||||
}
|
||||
|
||||
void CalendarTable::paintBorder(QPainter *p, int cell, int week, int weekDay, CellTypes type, const QDate &cellDate)
|
||||
{
|
||||
Q_UNUSED(cell);
|
||||
Q_UNUSED(cellDate);
|
||||
|
||||
if (type & Hovered) {
|
||||
p->fillRect(QRect(cellX(weekDay), cellY(week), d->cellW, d->cellH), d->highlightBrush);
|
||||
}
|
||||
|
||||
QString elementId;
|
||||
|
||||
if (type & Today) {
|
||||
elementId = "today";
|
||||
} else if (type & Selected) {
|
||||
elementId = "selected";
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
d->svg->paint(p, QRectF(cellX(weekDay) - 1, cellY(week) - 1,
|
||||
d->cellW + 1, d->cellH + 2),
|
||||
elementId);
|
||||
}
|
||||
|
||||
QString CalendarTable::cellSVGSuffix(int cell, int week, int weekDay, CellTypes type, const QDate &cellDate)
|
||||
{
|
||||
Q_UNUSED(week);
|
||||
Q_UNUSED(weekDay);
|
||||
Q_UNUSED(cellDate);
|
||||
return QString::number(cell) + (type & NotInCurrentMonth ? "-grayed" : "");
|
||||
}
|
||||
|
||||
void CalendarTable::paint(QPainter *p, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
||||
{
|
||||
Q_UNUSED(widget);
|
||||
int daysInWeek = d->calendar->daysInWeek(d->date);
|
||||
|
||||
// Draw weeks numbers column and day header
|
||||
QRectF r = boundingRect();
|
||||
d->svg->paint(p, QRectF(r.x() + d->centeringSpace, cellY(0), d->cellW,
|
||||
cellY(5) - cellY(0) - d->cellSpace), "weeksColumn");
|
||||
d->svg->paint(p, QRectF(r.x() + d->centeringSpace, r.y(),
|
||||
cellX(daysInWeek) - r.x() - d->cellSpace - d->centeringSpace, d->headerHeight), "weekDayHeader");
|
||||
|
||||
QList<CalendarCellBorder> borders;
|
||||
QList<CalendarCellBorder> hovers;
|
||||
QDate currentDate = QDate::currentDate(); //FIXME: calendar timezone
|
||||
|
||||
//kDebug() << "exposed: " << option->exposedRect;
|
||||
for (int week = 0; week < 5; week++) {
|
||||
for (int weekDay = 0; weekDay < daysInWeek; weekDay++) {
|
||||
|
||||
int x = cellX(weekDay);
|
||||
int y = cellY(week);
|
||||
|
||||
QRectF cellRect(x, y, d->cellW, d->cellH);
|
||||
if (!cellRect.intersects(option->exposedRect)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QDate cellDate(d->date.year(), d->date.month(), (week * 7) + (weekDay + 1));
|
||||
CalendarTable::CellTypes type(CalendarTable::NoType);
|
||||
// get cell info
|
||||
int cell = d->cell(week, weekDay + 1, &type, cellDate);
|
||||
|
||||
// check what kind of cell we are
|
||||
if (cellDate == currentDate) {
|
||||
type |= Today;
|
||||
}
|
||||
|
||||
if (cellDate == d->date) {
|
||||
type |= Selected;
|
||||
}
|
||||
|
||||
if (type != CalendarTable::NoType && type != CalendarTable::NotInCurrentMonth) {
|
||||
borders.append(CalendarCellBorder(cell, week, weekDay, type, cellDate));
|
||||
}
|
||||
|
||||
if (week == d->hoverWeek && weekDay == d->hoverDay) {
|
||||
type |= Hovered;
|
||||
hovers.append(CalendarCellBorder(cell, week, weekDay, type, cellDate));
|
||||
}
|
||||
|
||||
paintCell(p, cell, week, weekDay, type, cellDate);
|
||||
|
||||
if (weekDay == 0) {
|
||||
QRectF cellRect(r.x() + d->centeringSpace, y, d->cellW, d->cellH);
|
||||
d->svg->paint(p, cellRect, "week" + QString::number(d->calendar->weekNumber(cellDate)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw days
|
||||
if (option->exposedRect.intersects(QRect(r.x(), r.y(), r.width(), d->headerHeight))) {
|
||||
p->setPen(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
|
||||
int weekStartDay = d->calendar->weekStartDay();
|
||||
for (int i = 0; i < daysInWeek; i++){
|
||||
int weekDay = ((i + weekStartDay - 1) % daysInWeek) + 1;
|
||||
QString dayName = d->calendar->weekDayName(weekDay, KCalendarSystem::ShortDayName);
|
||||
p->drawText(QRectF(cellX(i), r.y(), d->cellW, d->headerHeight), Qt::AlignCenter, dayName);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw hovers
|
||||
foreach (const CalendarCellBorder &border, hovers) {
|
||||
p->save();
|
||||
paintBorder(p, border.cell, border.week, border.weekDay, border.type, border.date);
|
||||
p->restore();
|
||||
}
|
||||
|
||||
// Draw borders
|
||||
foreach (const CalendarCellBorder &border, borders) {
|
||||
p->save();
|
||||
paintBorder(p, border.cell, border.week, border.weekDay, border.type, border.date);
|
||||
p->restore();
|
||||
}
|
||||
|
||||
/*
|
||||
p->save();
|
||||
p->setPen(Qt::red);
|
||||
p->drawRect(option->exposedRect.adjusted(1, 1, -2, -2));
|
||||
p->restore();
|
||||
*/
|
||||
}
|
||||
|
||||
} //namespace Plasma
|
||||
|
||||
#include "calendartable.moc"
|
90
libplasmaclock/calendartable.h
Normal file
90
libplasmaclock/calendartable.h
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2008 Davide Bettio <davide.bettio@kdemail.net>
|
||||
*
|
||||
* This program 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, 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 Library 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 PLASMA_CALENDARWIDGET_H
|
||||
#define PLASMA_CALENDARWIDGET_H
|
||||
|
||||
#include <QtGui/QGraphicsWidget>
|
||||
|
||||
#include "plasmaclock_export.h"
|
||||
|
||||
#include <kcalendarsystem.h>
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
class CalendarTablePrivate;
|
||||
|
||||
class PLASMACLOCK_EXPORT CalendarTable : public QGraphicsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum CellType { NoType = 0,
|
||||
Today = 1,
|
||||
Selected = 2,
|
||||
Hovered = 4,
|
||||
NotInCurrentMonth = 8 };
|
||||
Q_DECLARE_FLAGS(CellTypes, CellType)
|
||||
|
||||
explicit CalendarTable(QGraphicsWidget *parent = 0);
|
||||
CalendarTable(const QDate &, QGraphicsWidget *parent = 0);
|
||||
~CalendarTable();
|
||||
|
||||
const KCalendarSystem *calendar () const;
|
||||
|
||||
bool setDate(const QDate &date);
|
||||
const QDate& date() const;
|
||||
|
||||
bool setCalendar(KCalendarSystem *calendar = 0);
|
||||
|
||||
Q_SIGNALS:
|
||||
void dateChanged(const QDate &cur, const QDate &old);
|
||||
void dateChanged(const QDate &date);
|
||||
void tableClicked();
|
||||
void displayedMonthChanged(int calendarSystemYear, int calendarSystemMonth);
|
||||
void displayedYearChanged(int calendarSystemYear, int calendarSystemMonth);
|
||||
|
||||
protected:
|
||||
int cellX(int weekDay);
|
||||
int cellY(int week);
|
||||
|
||||
void paint(QPainter *p, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
|
||||
void wheelEvent(QGraphicsSceneWheelEvent *event);
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event);
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
|
||||
void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
|
||||
void resizeEvent(QGraphicsSceneResizeEvent * event);
|
||||
|
||||
virtual void paintCell(QPainter *p, int cell, int week, int weekDay, CellTypes type, const QDate &cellDate);
|
||||
virtual void paintBorder(QPainter *p, int cell, int week, int weekDay, CellTypes type, const QDate &cellDate);
|
||||
virtual QString cellSVGSuffix(int cell, int week, int weekDay, CellTypes type, const QDate &cellDate);
|
||||
|
||||
private:
|
||||
Q_PRIVATE_SLOT(d, void setupThemedElements())
|
||||
|
||||
friend class CalendarTablePrivate;
|
||||
CalendarTablePrivate* const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(Plasma::CalendarTable::CellTypes)
|
||||
#endif
|
379
libplasmaclock/clockapplet.cpp
Normal file
379
libplasmaclock/clockapplet.cpp
Normal file
@ -0,0 +1,379 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007-2008 by Riccardo Iaconelli <riccardo@kde.org> *
|
||||
* Copyright (C) 2007-2008 by Sebastian Kuegler <sebas@kde.org> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
|
||||
***************************************************************************/
|
||||
|
||||
#include "clockapplet.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QStyleOptionGraphicsItem>
|
||||
#include <QtGui/QSpinBox>
|
||||
#include <QtCore/QTimeLine>
|
||||
#include <QtGui/QGraphicsProxyWidget>
|
||||
#include <QtGui/QGraphicsSceneMouseEvent>
|
||||
#include <QtGui/QGraphicsView>
|
||||
#include <QtCore/QDate>
|
||||
|
||||
#include <KColorScheme>
|
||||
#include <KConfigDialog>
|
||||
#include <KConfigGroup>
|
||||
#include <KDatePicker>
|
||||
#include <KDebug>
|
||||
#include <KDialog>
|
||||
#include <KGlobalSettings>
|
||||
|
||||
#include <plasma/containment.h>
|
||||
#include <plasma/corona.h>
|
||||
#include <plasma/dataengine.h>
|
||||
#include <plasma/dialog.h>
|
||||
#include <plasma/extender.h>
|
||||
#include <plasma/extenderitem.h>
|
||||
#include <plasma/theme.h>
|
||||
|
||||
#include "calendar.h"
|
||||
|
||||
#include "ui_timezonesConfig.h"
|
||||
|
||||
class ClockApplet::Private
|
||||
{
|
||||
public:
|
||||
Private()
|
||||
: timezone(ClockApplet::localTimezone())
|
||||
{}
|
||||
|
||||
Ui::timezonesConfig ui;
|
||||
QString timezone;
|
||||
QPoint clicked;
|
||||
QStringList selectedTimezones;
|
||||
QString prettyTimezone;
|
||||
|
||||
void addTzToTipText(QString &subText, QString tz)
|
||||
{
|
||||
Plasma::Applet applet;
|
||||
Plasma::DataEngine::Data data = applet.dataEngine("time")->query(tz);
|
||||
if (tz == "UTC") {
|
||||
subText += "<br><b>UTC</b> ";
|
||||
}
|
||||
else {
|
||||
subText += "<br><b>" + data["Timezone City"].toString().replace("_", " ")+"</b> ";
|
||||
}
|
||||
subText += KGlobal::locale()->formatTime(data["Time"].toTime(), false) + ", ";
|
||||
subText += KGlobal::locale()->formatDate(data["Date"].toDate());
|
||||
}
|
||||
};
|
||||
|
||||
ClockApplet::ClockApplet(QObject *parent, const QVariantList &args)
|
||||
: Plasma::PopupApplet(parent, args),
|
||||
d(new Private)
|
||||
{
|
||||
setPopupIcon(QIcon());
|
||||
}
|
||||
|
||||
ClockApplet::~ClockApplet()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void ClockApplet::toolTipAboutToShow()
|
||||
{
|
||||
updateContent();
|
||||
}
|
||||
|
||||
void ClockApplet::toolTipHidden()
|
||||
{
|
||||
Plasma::ToolTipManager::self()->clearContent(this);
|
||||
}
|
||||
|
||||
void ClockApplet::updateContent()
|
||||
{
|
||||
Plasma::ToolTipContent tipData;
|
||||
|
||||
{
|
||||
// the main text contains the current timezone's time and date
|
||||
Plasma::DataEngine::Data data = dataEngine("time")->query(currentTimezone());
|
||||
QString mainText = d->prettyTimezone + " ";
|
||||
mainText += KGlobal::locale()->formatTime(data["Time"].toTime(), false) + "<br>";
|
||||
mainText += KGlobal::locale()->formatDate(data["Date"].toDate());
|
||||
tipData.setMainText(mainText);
|
||||
}
|
||||
|
||||
QString subText;
|
||||
if (!isLocalTimezone()) {
|
||||
d->addTzToTipText(subText, localTimezone());
|
||||
}
|
||||
|
||||
foreach (const QString &tz, getSelectedTimezones()) {
|
||||
if (tz == currentTimezone()) {
|
||||
continue;
|
||||
}
|
||||
d->addTzToTipText(subText, tz);
|
||||
}
|
||||
|
||||
tipData.setSubText(subText);
|
||||
|
||||
// query for custom content
|
||||
Plasma::ToolTipContent customContent = toolTipContent();
|
||||
if (customContent.image().isNull()) {
|
||||
tipData.setImage(KIcon("chronometer").pixmap(IconSize(KIconLoader::Desktop)));
|
||||
} else {
|
||||
tipData.setImage(customContent.image());
|
||||
}
|
||||
|
||||
if (!customContent.mainText().isEmpty()) {
|
||||
// add their main text
|
||||
tipData.setMainText(customContent.mainText() + "<br>" + tipData.mainText());
|
||||
}
|
||||
|
||||
if (!customContent.subText().isEmpty()) {
|
||||
// add their sub text
|
||||
tipData.setSubText(customContent.subText() + "<br>" + tipData.subText());
|
||||
}
|
||||
|
||||
tipData.setAutohide(false);
|
||||
Plasma::ToolTipManager::self()->setContent(this, tipData);
|
||||
}
|
||||
|
||||
Plasma::ToolTipContent ClockApplet::toolTipContent()
|
||||
{
|
||||
return Plasma::ToolTipContent();
|
||||
}
|
||||
|
||||
void ClockApplet::createConfigurationInterface(KConfigDialog *parent)
|
||||
{
|
||||
createClockConfigurationInterface(parent);
|
||||
|
||||
QWidget *widget = new QWidget();
|
||||
d->ui.setupUi(widget);
|
||||
|
||||
parent->addPage(widget, i18n("Time Zones"), Applet::icon());
|
||||
|
||||
foreach (const QString &tz, d->selectedTimezones) {
|
||||
d->ui.timeZones->setSelected(tz, true);
|
||||
}
|
||||
|
||||
updateClockDefaultsTo();
|
||||
int defaultSelection = d->ui.clockDefaultsTo->findText(currentTimezone());
|
||||
if (defaultSelection >= 0) {
|
||||
d->ui.clockDefaultsTo->setCurrentIndex(defaultSelection);
|
||||
}
|
||||
|
||||
parent->setButtons( KDialog::Ok | KDialog::Cancel | KDialog::Apply );
|
||||
connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
|
||||
connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
|
||||
connect(d->ui.timeZones, SIGNAL(itemSelectionChanged()), this, SLOT(updateClockDefaultsTo()));
|
||||
|
||||
#if 0
|
||||
#ifdef CLOCK_APPLET_CONF
|
||||
ui.localTimeZone->setChecked(isLocalTimezone());
|
||||
ui.timeZones->setEnabled(!isLocalTimezone());
|
||||
foreach (const QString &str, selectedTimezones) {
|
||||
ui.timeZones->setSelected(str, true);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void ClockApplet::createClockConfigurationInterface(KConfigDialog *parent)
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
}
|
||||
|
||||
void ClockApplet::clockConfigAccepted()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ClockApplet::configAccepted()
|
||||
{
|
||||
KConfigGroup cg = config();
|
||||
|
||||
d->selectedTimezones = d->ui.timeZones->selection();
|
||||
cg.writeEntry("timeZones", d->selectedTimezones);
|
||||
|
||||
QString newTimezone;
|
||||
|
||||
if (d->ui.clockDefaultsTo->currentIndex() == 0) {
|
||||
//The first position in ui.clockDefaultsTo is "Local"
|
||||
newTimezone = localTimezone();
|
||||
} else {
|
||||
newTimezone = d->ui.clockDefaultsTo->currentText();
|
||||
}
|
||||
|
||||
changeEngineTimezone(currentTimezone(), newTimezone);
|
||||
setCurrentTimezone(newTimezone);
|
||||
|
||||
clockConfigAccepted();
|
||||
constraintsEvent(Plasma::SizeConstraint);
|
||||
update();
|
||||
|
||||
emit configNeedsSaving();
|
||||
}
|
||||
|
||||
void ClockApplet::updateClockDefaultsTo()
|
||||
{
|
||||
QString oldSelection = d->ui.clockDefaultsTo->currentText();
|
||||
d->ui.clockDefaultsTo->clear();
|
||||
d->ui.clockDefaultsTo->addItems(d->ui.timeZones->selection());
|
||||
d->ui.clockDefaultsTo->insertItem(0, "Local");
|
||||
int newPosition = d->ui.clockDefaultsTo->findText(oldSelection);
|
||||
if (newPosition >= 0) {
|
||||
d->ui.clockDefaultsTo->setCurrentIndex(newPosition);
|
||||
}
|
||||
if (d->ui.clockDefaultsTo->count() > 1) {
|
||||
d->ui.clockDefaultsTo->setEnabled(true);
|
||||
}
|
||||
else {
|
||||
// Only "Local" in ui.clockDefaultsTo
|
||||
d->ui.clockDefaultsTo->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ClockApplet::changeEngineTimezone(const QString &oldTimezone, const QString &newTimezone)
|
||||
{
|
||||
// reimplemented by subclasses to get the new data
|
||||
Q_UNUSED(oldTimezone);
|
||||
Q_UNUSED(newTimezone);
|
||||
}
|
||||
|
||||
void ClockApplet::wheelEvent(QGraphicsSceneWheelEvent *event)
|
||||
{
|
||||
if (d->selectedTimezones.count() < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString newTimezone;
|
||||
|
||||
if (isLocalTimezone()) {
|
||||
if (event->delta() > 0) {
|
||||
newTimezone = d->selectedTimezones.last();
|
||||
} else {
|
||||
newTimezone = d->selectedTimezones.first();
|
||||
}
|
||||
} else {
|
||||
int current = d->selectedTimezones.indexOf(currentTimezone());
|
||||
|
||||
if (event->delta() > 0) {
|
||||
int previous = current - 1;
|
||||
if (previous < 0) {
|
||||
newTimezone = localTimezone();
|
||||
} else {
|
||||
newTimezone = d->selectedTimezones.at(previous);
|
||||
}
|
||||
} else {
|
||||
int next = current + 1;
|
||||
if (next > d->selectedTimezones.count() - 1) {
|
||||
newTimezone = localTimezone();
|
||||
} else {
|
||||
newTimezone = d->selectedTimezones.at(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changeEngineTimezone(currentTimezone(), newTimezone);
|
||||
setCurrentTimezone(newTimezone);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void ClockApplet::initExtenderItem(Plasma::ExtenderItem *item)
|
||||
{
|
||||
Plasma::Calendar *calendar = new Plasma::Calendar;
|
||||
calendar->setMinimumSize(QSize(200, 180));
|
||||
|
||||
Plasma::DataEngine::Data data = dataEngine("time")->query(currentTimezone());
|
||||
QDate date = data["Date"].toDate();
|
||||
if (date.isValid()) {
|
||||
calendar->setDate(date);
|
||||
}
|
||||
|
||||
item->setWidget(calendar);
|
||||
item->setTitle(i18n("Calendar"));
|
||||
}
|
||||
|
||||
void ClockApplet::init()
|
||||
{
|
||||
KConfigGroup cg = config();
|
||||
d->selectedTimezones = cg.readEntry("timeZones", QStringList());
|
||||
d->timezone = cg.readEntry("timezone", d->timezone);
|
||||
if (d->timezone == "UTC") {
|
||||
d->prettyTimezone = d->timezone;
|
||||
} else {
|
||||
if (!isLocalTimezone()) {
|
||||
QStringList tzParts = d->timezone.split("/");
|
||||
d->prettyTimezone = tzParts.value(1);
|
||||
} else {
|
||||
d->prettyTimezone = localTimezone();
|
||||
}
|
||||
}
|
||||
|
||||
//avoid duplication
|
||||
if (!extender()->item("calendar")) {
|
||||
Plasma::ExtenderItem *eItem = new Plasma::ExtenderItem(extender());
|
||||
eItem->setName("calendar");
|
||||
initExtenderItem(eItem);
|
||||
}
|
||||
|
||||
Plasma::ToolTipManager::self()->registerWidget(this);
|
||||
}
|
||||
|
||||
void ClockApplet::setCurrentTimezone(const QString &tz)
|
||||
{
|
||||
if (d->timezone == tz) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->timezone = tz;
|
||||
if (tz == "UTC") {
|
||||
d->prettyTimezone = tz;
|
||||
} else {
|
||||
QStringList tzParts = tz.split("/");
|
||||
d->prettyTimezone = tzParts.value(1);
|
||||
}
|
||||
KConfigGroup cg = config();
|
||||
cg.writeEntry("timezone", tz);
|
||||
emit configNeedsSaving();
|
||||
}
|
||||
|
||||
QString ClockApplet::currentTimezone() const
|
||||
{
|
||||
return d->timezone;
|
||||
}
|
||||
|
||||
QString ClockApplet::prettyTimezone() const
|
||||
{
|
||||
return d->prettyTimezone;
|
||||
}
|
||||
|
||||
QStringList ClockApplet::getSelectedTimezones() const
|
||||
{
|
||||
return d->selectedTimezones;
|
||||
}
|
||||
|
||||
bool ClockApplet::isLocalTimezone() const
|
||||
{
|
||||
return d->timezone == localTimezone();
|
||||
}
|
||||
|
||||
QString ClockApplet::localTimezone()
|
||||
{
|
||||
return "Local";
|
||||
}
|
||||
|
||||
#include "clockapplet.moc"
|
82
libplasmaclock/clockapplet.h
Normal file
82
libplasmaclock/clockapplet.h
Normal file
@ -0,0 +1,82 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007-2008 by Riccardo Iaconelli <riccardo@kde.org> *
|
||||
* Copyright (C) 2007-2008 by Sebastian Kuegler <sebas@kde.org> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef CLOCKAPPLET_H
|
||||
#define CLOCKAPPLET_H
|
||||
|
||||
#include <QtCore/QTime>
|
||||
#include <QtCore/QDate>
|
||||
|
||||
#include <plasma/dataengine.h>
|
||||
#include <plasma/dialog.h>
|
||||
#include <plasma/popupapplet.h>
|
||||
#include <plasma/tooltipmanager.h>
|
||||
|
||||
#include "plasmaclock_export.h"
|
||||
|
||||
class KDialog;
|
||||
class KConfigDialog;
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
class Svg;
|
||||
}
|
||||
|
||||
class PLASMACLOCK_EXPORT ClockApplet : public Plasma::PopupApplet
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ClockApplet(QObject *parent, const QVariantList &args);
|
||||
~ClockApplet();
|
||||
|
||||
void init();
|
||||
|
||||
QString currentTimezone() const;
|
||||
QString prettyTimezone() const;
|
||||
bool isLocalTimezone() const;
|
||||
QStringList getSelectedTimezones() const;
|
||||
|
||||
static QString localTimezone();
|
||||
|
||||
public Q_SLOTS:
|
||||
void toolTipAboutToShow();
|
||||
void toolTipHidden();
|
||||
|
||||
protected:
|
||||
virtual void createClockConfigurationInterface(KConfigDialog *parent);
|
||||
virtual void clockConfigAccepted();
|
||||
virtual void changeEngineTimezone(const QString &oldTimezone, const QString &newTimezone);
|
||||
virtual Plasma::ToolTipContent toolTipContent();
|
||||
void wheelEvent(QGraphicsSceneWheelEvent *event);
|
||||
void createConfigurationInterface(KConfigDialog *parent);
|
||||
void initExtenderItem(Plasma::ExtenderItem *item);
|
||||
void updateContent();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void setCurrentTimezone(const QString &tz);
|
||||
void configAccepted();
|
||||
void updateClockDefaultsTo();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
#endif
|
71
libplasmaclock/clocknumber.cpp
Normal file
71
libplasmaclock/clocknumber.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Riccardo Iaconelli <riccardo@kde.org> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
|
||||
***************************************************************************/
|
||||
|
||||
#include "clocknumber.h"
|
||||
|
||||
class Number::Private
|
||||
{
|
||||
public:
|
||||
char data;
|
||||
};
|
||||
|
||||
Number::Number(QChar value)
|
||||
: d(new Private)
|
||||
{
|
||||
d->data = value.toAscii();
|
||||
}
|
||||
|
||||
Number::~Number()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void Number::operator--()
|
||||
{
|
||||
if (d->data == '0') {
|
||||
d->data = '9';
|
||||
} else {
|
||||
d->data--;
|
||||
}
|
||||
}
|
||||
|
||||
void Number::operator++()
|
||||
{
|
||||
if (d->data == '9') {
|
||||
d->data = '0';
|
||||
} else {
|
||||
d->data++;
|
||||
}
|
||||
}
|
||||
|
||||
void Number::operator=(QChar value)
|
||||
{
|
||||
d->data = value.toAscii();
|
||||
}
|
||||
|
||||
bool Number::operator==(char value)
|
||||
{
|
||||
return d->data == value;
|
||||
}
|
||||
|
||||
Number::operator char()
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
43
libplasmaclock/clocknumber.h
Normal file
43
libplasmaclock/clocknumber.h
Normal file
@ -0,0 +1,43 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Riccardo Iaconelli <riccardo@kde.org> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef CLOCKNUMBER_H
|
||||
#define CLOCKNUMBER_H
|
||||
|
||||
#include <QtCore/QChar>
|
||||
#include "plasmaclock_export.h"
|
||||
|
||||
class PLASMACLOCK_EXPORT Number
|
||||
{
|
||||
public:
|
||||
Number(QChar value);
|
||||
~Number();
|
||||
void operator--();
|
||||
void operator++();
|
||||
void operator=(QChar value);
|
||||
bool operator==(char value);
|
||||
operator char();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
40
libplasmaclock/plasmaclock_export.h
Normal file
40
libplasmaclock/plasmaclock_export.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* This file is part of the KDE project
|
||||
Copyright (C) 2007 David Faure <faure@kde.org>
|
||||
|
||||
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 PLASMACLOCK_EXPORT_H
|
||||
#define PLASMACLOCK_EXPORT_H
|
||||
|
||||
/* needed for KDE_EXPORT and KDE_IMPORT macros */
|
||||
#include <kdemacros.h>
|
||||
|
||||
#ifndef PLASMACLOCK_EXPORT
|
||||
# if defined(MAKE_PLASMACLOCK_LIB)
|
||||
/* We are building this library */
|
||||
# define PLASMACLOCK_EXPORT KDE_EXPORT
|
||||
# else
|
||||
/* We are using this library */
|
||||
# define PLASMACLOCK_EXPORT KDE_IMPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
# ifndef PLASMACLOCK_EXPORT_DEPRECATED
|
||||
# define PLASMACLOCK_EXPORT_DEPRECATED KDE_DEPRECATED PLASMACLOCK_EXPORT
|
||||
# endif
|
||||
|
||||
#endif
|
96
libplasmaclock/timezonesConfig.ui
Normal file
96
libplasmaclock/timezonesConfig.ui
Normal file
@ -0,0 +1,96 @@
|
||||
<ui version="4.0" >
|
||||
<class>timezonesConfig</class>
|
||||
<widget class="QWidget" name="timezonesConfig" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>308</width>
|
||||
<height>227</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="KTimeZoneWidget" name="timeZones" >
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>150</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip" >
|
||||
<string>Select one or several time zones.</string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:10pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Your <span style=" font-weight:600;">Local</span> time and time zone are defined in System Settings, in the Date and Time tab. As default, your plasma clock will use this setting.</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The plasma clock tooltip can display the time in several other time zones: to do so, select one or several more time zones in the list. Click on a line to select it and click on it again to deselect it. </p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">After you validate your choices with the OK button, when your mouse is over the clock, a tooltip will display the time in all the selected time zones.</p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To select a <span style=" font-weight:600;">Default</span> time zone: you can either scroll over the clock with your mouse wheel and set the one you want or you can set it with "Clock defaults to:". .</p></body></html></string>
|
||||
</property>
|
||||
<property name="selectionMode" >
|
||||
<enum>QAbstractItemView::MultiSelection</enum>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text" >
|
||||
<string>Area</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text" >
|
||||
<string>Region</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text" >
|
||||
<string>Comment</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="text" >
|
||||
<string>Clock defaults to:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QComboBox" name="clockDefaultsTo" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip" >
|
||||
<string>The time the clock will display</string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string>The clock will display the time for the selected default zone.
|
||||
Local is the time you set in System Settings.</string>
|
||||
</property>
|
||||
<property name="insertPolicy" >
|
||||
<enum>QComboBox::InsertAlphabetically</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KTimeZoneWidget</class>
|
||||
<extends>QTreeWidget</extends>
|
||||
<header>ktimezonewidget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
127
libplasmaclock/toolbutton.cpp
Normal file
127
libplasmaclock/toolbutton.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2008 Marco Martin <notmart@gmail.com>
|
||||
* Copyright 2008 Aaron Seigo <aseigo@kde.org>
|
||||
*
|
||||
* This program 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, 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 Library 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 "toolbutton.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QPainter>
|
||||
#include <QPaintEvent>
|
||||
#include <QStyle>
|
||||
#include <QStyleOptionToolButton>
|
||||
|
||||
#include <plasma/paintutils.h>
|
||||
#include <plasma/theme.h>
|
||||
#include <plasma/framesvg.h>
|
||||
|
||||
ToolButton::ToolButton()
|
||||
: QToolButton(),
|
||||
m_action(0)
|
||||
{
|
||||
setAttribute(Qt::WA_NoSystemBackground);
|
||||
|
||||
m_background = new Plasma::FrameSvg(this);
|
||||
m_background->setImagePath("widgets/button");
|
||||
m_background->setCacheAllRenderedFrames(true);
|
||||
m_background->setElementPrefix("plain");
|
||||
}
|
||||
|
||||
|
||||
ToolButton::ToolButton(QWidget *parent)
|
||||
: QToolButton(parent),
|
||||
m_action(0)
|
||||
{
|
||||
m_background = new Plasma::FrameSvg(this);
|
||||
m_background->setImagePath("widgets/button");
|
||||
m_background->setCacheAllRenderedFrames(true);
|
||||
m_background->setElementPrefix("plain");
|
||||
}
|
||||
|
||||
void ToolButton::setAction(QAction *action)
|
||||
{
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_action) {
|
||||
disconnect(m_action, SIGNAL(changed()), this, SLOT(syncToAction()));
|
||||
disconnect(this, SIGNAL(clicked()), m_action, SLOT(trigger()));
|
||||
}
|
||||
|
||||
m_action = action;
|
||||
connect(m_action, SIGNAL(changed()), this, SLOT(syncToAction()));
|
||||
connect(this, SIGNAL(clicked()), m_action, SLOT(trigger()));
|
||||
connect(m_action, SIGNAL(destroyed(QObject*)), this, SLOT(actionDestroyed(QObject*)));
|
||||
syncToAction();
|
||||
}
|
||||
|
||||
void ToolButton::syncToAction()
|
||||
{
|
||||
if (!m_action) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIcon(m_action->icon());
|
||||
setText(m_action->text());
|
||||
|
||||
if (toolButtonStyle() == Qt::ToolButtonIconOnly) {
|
||||
setToolTip(m_action->text());
|
||||
}
|
||||
|
||||
setCheckable(m_action->isCheckable());
|
||||
if (m_action->actionGroup()) {
|
||||
setAutoExclusive(m_action->actionGroup()->isExclusive());
|
||||
}
|
||||
|
||||
setEnabled(m_action->isEnabled());
|
||||
}
|
||||
|
||||
void ToolButton::actionDestroyed(QObject *)
|
||||
{
|
||||
m_action = 0;
|
||||
}
|
||||
|
||||
void ToolButton::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
|
||||
QPainter painter(this);
|
||||
|
||||
QStyleOptionToolButton buttonOpt;
|
||||
initStyleOption(&buttonOpt);
|
||||
|
||||
if ((buttonOpt.state & QStyle::State_MouseOver) || (buttonOpt.state & QStyle::State_On)) {
|
||||
if (buttonOpt.state & QStyle::State_Sunken || (buttonOpt.state & QStyle::State_On)) {
|
||||
m_background->setElementPrefix("pressed");
|
||||
} else {
|
||||
m_background->setElementPrefix("normal");
|
||||
}
|
||||
m_background->resizeFrame(size());
|
||||
m_background->paintFrame(&painter);
|
||||
|
||||
buttonOpt.palette.setColor(QPalette::ButtonText, Plasma::Theme::defaultTheme()->color(Plasma::Theme::ButtonTextColor));
|
||||
} else {
|
||||
buttonOpt.palette.setColor(QPalette::ButtonText, Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
|
||||
}
|
||||
|
||||
style()->drawControl(QStyle::CE_ToolButtonLabel, &buttonOpt, &painter, this);
|
||||
}
|
||||
|
||||
#include "toolbutton.moc"
|
||||
|
53
libplasmaclock/toolbutton.h
Normal file
53
libplasmaclock/toolbutton.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2008 Marco Martin <notmart@gmail.com>
|
||||
* Copyright 2008 Aaron Seigo <aseigo@kde.org>
|
||||
*
|
||||
* This program 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, 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 Library 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 TOOLBUTTON_H
|
||||
#define TOOLBUTTON_H
|
||||
|
||||
#include <QToolButton>
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
class FrameSvg;
|
||||
}
|
||||
|
||||
class ToolButton: public QToolButton
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ToolButton();
|
||||
ToolButton(QWidget *parent);
|
||||
void setAction(QAction *action);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
|
||||
protected slots:
|
||||
void actionDestroyed(QObject *);
|
||||
void syncToAction();
|
||||
|
||||
private:
|
||||
QAction *m_action;
|
||||
Plasma::FrameSvg *m_background;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
41
nepomukquery/CMakeLists.txt
Normal file
41
nepomukquery/CMakeLists.txt
Normal file
@ -0,0 +1,41 @@
|
||||
project(nepomukquery)
|
||||
|
||||
include_directories(
|
||||
${QT_INCLUDES}
|
||||
${KDE4_INCLUDES}
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${SOPRANO_INCLUDE_DIR}
|
||||
${NEPOMUK_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS})# -fPIC)
|
||||
|
||||
set(nepomukquery_SRC
|
||||
result.cpp
|
||||
term.cpp
|
||||
query.cpp
|
||||
queryparser.cpp
|
||||
dbusoperators.cpp
|
||||
)
|
||||
|
||||
kde4_add_library(nepomukquery SHARED ${nepomukquery_SRC}
|
||||
)
|
||||
|
||||
set_target_properties(nepomukquery PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION})
|
||||
|
||||
target_link_libraries(nepomukquery
|
||||
${QT_QTCORE_LIBRARY}
|
||||
${KDE4_KDECORE_LIBS}
|
||||
${SOPRANO_LIBRARIES}
|
||||
)
|
||||
|
||||
install(TARGETS nepomukquery ${INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
|
||||
install(FILES
|
||||
nepomukquery_export.h
|
||||
queryparser.h
|
||||
result.h
|
||||
term.h
|
||||
query.h
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/nepomuk
|
||||
)
|
2
nepomukquery/Messages.sh
Executable file
2
nepomukquery/Messages.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#! /usr/bin/env bash
|
||||
$XGETTEXT *.cpp -o $podir/nepomuksearch.pot
|
341
nepomukquery/dbusoperators.cpp
Normal file
341
nepomukquery/dbusoperators.cpp
Normal file
@ -0,0 +1,341 @@
|
||||
/*
|
||||
Copyright (c) 2008 Sebastian Trueg <trueg@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2 as published by the Free Software Foundation.
|
||||
|
||||
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 "dbusoperators.h"
|
||||
|
||||
#include <QtDBus/QDBusMetaType>
|
||||
|
||||
|
||||
Q_DECLARE_METATYPE(Nepomuk::Search::Result)
|
||||
Q_DECLARE_METATYPE(Nepomuk::Search::Term)
|
||||
Q_DECLARE_METATYPE(Nepomuk::Search::Query)
|
||||
Q_DECLARE_METATYPE(Soprano::Node)
|
||||
Q_DECLARE_METATYPE(QList<int>)
|
||||
Q_DECLARE_METATYPE(QList<Nepomuk::Search::Result>)
|
||||
|
||||
|
||||
void Nepomuk::Search::registerDBusTypes()
|
||||
{
|
||||
qDBusRegisterMetaType<Nepomuk::Search::Result>();
|
||||
qDBusRegisterMetaType<QList<Nepomuk::Search::Result> >();
|
||||
qDBusRegisterMetaType<Nepomuk::Search::Term>();
|
||||
qDBusRegisterMetaType<Nepomuk::Search::Query>();
|
||||
qDBusRegisterMetaType<Soprano::Node>();
|
||||
}
|
||||
|
||||
|
||||
QDBusArgument& operator<<( QDBusArgument& arg, const Nepomuk::Search::Result& result )
|
||||
{
|
||||
//
|
||||
// Signature: (sda{s(isss)})
|
||||
//
|
||||
|
||||
arg.beginStructure();
|
||||
|
||||
arg << result.resourceUri().toString() << result.score();
|
||||
|
||||
arg.beginMap( QVariant::String, qMetaTypeId<Soprano::Node>() );
|
||||
|
||||
QHash<QUrl, Soprano::Node> rp = result.requestProperties();
|
||||
for ( QHash<QUrl, Soprano::Node>::const_iterator it = rp.constBegin(); it != rp.constEnd(); ++it ) {
|
||||
arg.beginMapEntry();
|
||||
arg << it.key().toString() << it.value();
|
||||
arg.endMapEntry();
|
||||
}
|
||||
|
||||
arg.endMap();
|
||||
|
||||
arg.endStructure();
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
const QDBusArgument& operator>>( const QDBusArgument& arg, Nepomuk::Search::Result& result )
|
||||
{
|
||||
//
|
||||
// Signature: (sda{s(isss)})
|
||||
//
|
||||
|
||||
arg.beginStructure();
|
||||
QString uri;
|
||||
double score = 0.0;
|
||||
|
||||
arg >> uri >> score;
|
||||
result = Nepomuk::Search::Result( QUrl( uri ), score );
|
||||
|
||||
arg.beginMap();
|
||||
while ( !arg.atEnd() ) {
|
||||
QString rs;
|
||||
Soprano::Node node;
|
||||
arg.beginMapEntry();
|
||||
arg >> rs >> node;
|
||||
arg.endMapEntry();
|
||||
result.addRequestProperty( QUrl( rs ), node );
|
||||
}
|
||||
arg.endMap();
|
||||
|
||||
arg.endStructure();
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
QDBusArgument& operator<<( QDBusArgument& arg, const Nepomuk::Search::Term& term )
|
||||
{
|
||||
//
|
||||
// Signature: (ii(isss)sss)
|
||||
// i -> type
|
||||
// i -> comparator type
|
||||
// (isss) -> Soprano::LiteralValue encoded as a Soprano::Node for simplicity
|
||||
// s -> resource
|
||||
// s -> field
|
||||
// s -> property
|
||||
//
|
||||
|
||||
arg.beginStructure();
|
||||
arg << ( int )term.type()
|
||||
<< ( int )term.comparator()
|
||||
<< Soprano::Node( term.value() )
|
||||
<< term.resource().toString()
|
||||
<< term.field()
|
||||
<< term.property().toString();
|
||||
arg.endStructure();
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
const QDBusArgument& operator>>( const QDBusArgument& arg, Nepomuk::Search::Term& term )
|
||||
{
|
||||
//
|
||||
// Signature: (ii(isss)sss)
|
||||
// i -> type
|
||||
// i -> comparator type
|
||||
// (isss) -> Soprano::LiteralValue encoded as a Soprano::Node for simplicity
|
||||
// s -> resource
|
||||
// s -> field
|
||||
// s -> property
|
||||
//
|
||||
|
||||
arg.beginStructure();
|
||||
int type = Nepomuk::Search::Term::InvalidTerm;
|
||||
int comparator = Nepomuk::Search::Term::Equal;
|
||||
Soprano::Node valueNode;
|
||||
QString resource, field, property;
|
||||
arg >> type
|
||||
>> comparator
|
||||
>> valueNode
|
||||
>> resource
|
||||
>> field
|
||||
>> property;
|
||||
term.setType( Nepomuk::Search::Term::Type( type ) );
|
||||
term.setComparator( Nepomuk::Search::Term::Comparator( comparator ) );
|
||||
if ( valueNode.isLiteral() )
|
||||
term.setValue( valueNode.literal() );
|
||||
if ( !resource.isEmpty() )
|
||||
term.setResource( QUrl( resource ) );
|
||||
if ( !field.isEmpty() )
|
||||
term.setField( field );
|
||||
if ( !property.isEmpty() )
|
||||
term.setProperty( QUrl( property ) );
|
||||
arg.endStructure();
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
// streaming a Query object is a bit tricky as it is a set of nested Term objects
|
||||
// DBus does not allow arbitrary nesting of objects, thus we use a little trick:
|
||||
// We store all used Term objects in a list and use integer indices pointing into
|
||||
// this list to describe the nesting within the Term objects. This also means that
|
||||
// a Term's subTerm list is replaced with a list of indices
|
||||
namespace {
|
||||
/**
|
||||
* Build term relations for the last term in the list
|
||||
*/
|
||||
void buildTermRelations( QList<Nepomuk::Search::Term>& terms, QHash<int, QList<int> >& termRelations ) {
|
||||
QList<Nepomuk::Search::Term> subTerms = terms.last().subTerms();
|
||||
int termIndex = terms.count()-1;
|
||||
for ( int i = 0; i < subTerms.count(); ++i ) {
|
||||
terms.append( subTerms[i] );
|
||||
termRelations[termIndex].append( terms.count()-1 );
|
||||
buildTermRelations( terms, termRelations );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QDBusArgument& operator<<( QDBusArgument& arg, const Nepomuk::Search::Query& query )
|
||||
{
|
||||
//
|
||||
// Signature: (isa(ii(isss)sss)a{iai}ia{sb})
|
||||
// i -> type
|
||||
// s -> sparql query
|
||||
// a(ii(isss)sss) -> array of terms (first is root term)
|
||||
// a{iai} -> hash of term relations
|
||||
// i -> limit
|
||||
// a{sb} -> request properties
|
||||
//
|
||||
|
||||
arg.beginStructure();
|
||||
|
||||
arg << ( int )query.type() << query.sparqlQuery();
|
||||
|
||||
QList<Nepomuk::Search::Term> terms;
|
||||
QHash<int, QList<int> > termRelations;
|
||||
if ( query.type() == Nepomuk::Search::Query::PlainQuery ) {
|
||||
terms.append( query.term() );
|
||||
buildTermRelations( terms, termRelations );
|
||||
}
|
||||
arg << terms;
|
||||
|
||||
arg.beginMap( QVariant::Int, qMetaTypeId<QList<int> >() );
|
||||
for( QHash<int, QList<int> >::const_iterator it = termRelations.constBegin();
|
||||
it != termRelations.constEnd(); ++it ) {
|
||||
arg.beginMapEntry();
|
||||
arg << it.key() << it.value();
|
||||
arg.endMapEntry();
|
||||
}
|
||||
arg.endMap();
|
||||
arg << query.limit();
|
||||
|
||||
arg.beginMap( QVariant::String, QVariant::Bool );
|
||||
QList<Nepomuk::Search::Query::RequestProperty> requestProperties = query.requestProperties();
|
||||
foreach( const Nepomuk::Search::Query::RequestProperty& rp, requestProperties ) {
|
||||
arg.beginMapEntry();
|
||||
arg << rp.first.toString() << rp.second;
|
||||
arg.endMapEntry();
|
||||
}
|
||||
arg.endMap();
|
||||
|
||||
arg.endStructure();
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
Nepomuk::Search::Term rebuildTermFromTermList( const QList<Nepomuk::Search::Term>& terms,
|
||||
const QHash<int, QList<int> >& termRelations,
|
||||
int index = 0 ) {
|
||||
Nepomuk::Search::Term root = terms[index];
|
||||
foreach( int i, termRelations[index] ) {
|
||||
root.addSubTerm( rebuildTermFromTermList( terms, termRelations, i ) );
|
||||
}
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
const QDBusArgument& operator>>( const QDBusArgument& arg, Nepomuk::Search::Query& query )
|
||||
{
|
||||
//
|
||||
// Signature: (isa(ii(isss)sss)a{iai}ia{sb})
|
||||
// i -> type
|
||||
// s -> sparql query
|
||||
// a(ii(isss)sss) -> array of terms (first is root term)
|
||||
// a{iai} -> hash of term relations
|
||||
// i -> limit
|
||||
// a{sb} -> request properties
|
||||
//
|
||||
|
||||
arg.beginStructure();
|
||||
|
||||
int type = Nepomuk::Search::Query::InvalidQuery;
|
||||
QString sparqlQuery;
|
||||
QList<Nepomuk::Search::Term> terms;
|
||||
QHash<int, QList<int> > termRelations;
|
||||
int limit = 0;
|
||||
|
||||
arg >> type
|
||||
>> sparqlQuery
|
||||
>> terms;
|
||||
|
||||
arg.beginMap();
|
||||
while ( !arg.atEnd() ) {
|
||||
int termIndex = 0;
|
||||
QList<int> indices;
|
||||
arg.beginMapEntry();
|
||||
arg >> termIndex >> indices;
|
||||
arg.endMapEntry();
|
||||
termRelations.insert( termIndex, indices );
|
||||
}
|
||||
arg.endMap();
|
||||
|
||||
arg >> limit;
|
||||
|
||||
arg.beginMap();
|
||||
while ( !arg.atEnd() ) {
|
||||
QString prop;
|
||||
bool optional = true;
|
||||
arg.beginMapEntry();
|
||||
arg >> prop >> optional;
|
||||
arg.endMapEntry();
|
||||
query.addRequestProperty( QUrl( prop ), optional );
|
||||
}
|
||||
arg.endMap();
|
||||
|
||||
arg.endStructure();
|
||||
|
||||
if ( Nepomuk::Search::Query::Type( type ) == Nepomuk::Search::Query::PlainQuery ) {
|
||||
query.setTerm( rebuildTermFromTermList( terms, termRelations ) );
|
||||
}
|
||||
else {
|
||||
query.setSparqlQuery( sparqlQuery );
|
||||
}
|
||||
query.setLimit( limit );
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
QDBusArgument& operator<<( QDBusArgument& arg, const Soprano::Node& node )
|
||||
{
|
||||
//
|
||||
// Signature: (isss)
|
||||
//
|
||||
arg.beginStructure();
|
||||
arg << ( int )node.type() << node.toString() << node.language() << node.dataType().toString();
|
||||
arg.endStructure();
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
const QDBusArgument& operator>>( const QDBusArgument& arg, Soprano::Node& node )
|
||||
{
|
||||
//
|
||||
// Signature: (isss)
|
||||
//
|
||||
arg.beginStructure();
|
||||
int type;
|
||||
QString value, language, dataTypeUri;
|
||||
arg >> type >> value >> language >> dataTypeUri;
|
||||
if ( type == Soprano::Node::LiteralNode ) {
|
||||
node = Soprano::Node( Soprano::LiteralValue::fromString( value, dataTypeUri ), language );
|
||||
}
|
||||
else if ( type == Soprano::Node::ResourceNode ) {
|
||||
node = Soprano::Node( QUrl( value ) );
|
||||
}
|
||||
else if ( type == Soprano::Node::BlankNode ) {
|
||||
node = Soprano::Node( value );
|
||||
}
|
||||
else {
|
||||
node = Soprano::Node();
|
||||
}
|
||||
arg.endStructure();
|
||||
return arg;
|
||||
}
|
48
nepomukquery/dbusoperators.h
Normal file
48
nepomukquery/dbusoperators.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
Copyright (c) 2008 Sebastian Trueg <trueg@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2 as published by the Free Software Foundation.
|
||||
|
||||
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 _NEPOMUK_SEARCH_DBUS_OPERATORS_H_
|
||||
#define _NEPOMUK_SEARCH_DBUS_OPERATORS_H_
|
||||
|
||||
#include <QtDBus/QDBusArgument>
|
||||
|
||||
#include "result.h"
|
||||
#include "query.h"
|
||||
#include "term.h"
|
||||
|
||||
#include "nepomukquery_export.h"
|
||||
|
||||
namespace Nepomuk {
|
||||
namespace Search {
|
||||
NEPOMUKQUERY_EXPORT void registerDBusTypes();
|
||||
}
|
||||
}
|
||||
|
||||
NEPOMUKQUERY_EXPORT QDBusArgument& operator<<( QDBusArgument& arg, const Soprano::Node& );
|
||||
NEPOMUKQUERY_EXPORT const QDBusArgument& operator>>( const QDBusArgument& arg, Soprano::Node& );
|
||||
|
||||
NEPOMUKQUERY_EXPORT QDBusArgument& operator<<( QDBusArgument& arg, const Nepomuk::Search::Term& term );
|
||||
NEPOMUKQUERY_EXPORT const QDBusArgument& operator>>( const QDBusArgument& arg, Nepomuk::Search::Term& );
|
||||
|
||||
NEPOMUKQUERY_EXPORT QDBusArgument& operator<<( QDBusArgument& arg, const Nepomuk::Search::Query& query );
|
||||
NEPOMUKQUERY_EXPORT const QDBusArgument& operator>>( const QDBusArgument& arg, Nepomuk::Search::Query& );
|
||||
|
||||
NEPOMUKQUERY_EXPORT QDBusArgument& operator<<( QDBusArgument& arg, const Nepomuk::Search::Result& );
|
||||
NEPOMUKQUERY_EXPORT const QDBusArgument& operator>>( const QDBusArgument& arg, Nepomuk::Search::Result& );
|
||||
|
||||
#endif
|
36
nepomukquery/nepomukquery_export.h
Normal file
36
nepomukquery/nepomukquery_export.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* This file is part of the KDE project
|
||||
Copyright (C) 2007 David Faure <faure@kde.org>
|
||||
|
||||
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 NEPOMUKQUERY_EXPORT_H
|
||||
#define NEPOMUKQUERY_EXPORT_H
|
||||
|
||||
/* needed for KDE_EXPORT and KDE_IMPORT macros */
|
||||
#include <kdemacros.h>
|
||||
|
||||
#ifndef NEPOMUKQUERY_EXPORT
|
||||
# if defined(MAKE_NEPOMUKQUERY_LIB)
|
||||
/* We are building this library */
|
||||
# define NEPOMUKQUERY_EXPORT KDE_EXPORT
|
||||
# else
|
||||
/* We are using this library */
|
||||
# define NEPOMUKQUERY_EXPORT KDE_IMPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
195
nepomukquery/query.cpp
Normal file
195
nepomukquery/query.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
/*
|
||||
This file is part of the Nepomuk KDE project.
|
||||
Copyright (C) 2008 Sebastian Trueg <trueg@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2 as published by the Free Software Foundation.
|
||||
|
||||
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 "query.h"
|
||||
#include "term.h"
|
||||
|
||||
#include <QtCore/QSharedData>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
|
||||
class Nepomuk::Search::Query::Private : public QSharedData
|
||||
{
|
||||
public:
|
||||
Private()
|
||||
: type( InvalidQuery ),
|
||||
limit( 0 ) {
|
||||
}
|
||||
|
||||
Type type;
|
||||
Term term;
|
||||
QString sparqlQuery;
|
||||
int limit;
|
||||
|
||||
QList<RequestProperty> requestProperties;
|
||||
};
|
||||
|
||||
|
||||
Nepomuk::Search::Query::Query()
|
||||
: d( new Private() )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Nepomuk::Search::Query::Query( const Query& other )
|
||||
{
|
||||
d = other.d;
|
||||
}
|
||||
|
||||
|
||||
Nepomuk::Search::Query::Query( const Term& term )
|
||||
: d ( new Private() )
|
||||
{
|
||||
d->type = PlainQuery;
|
||||
d->term = term;
|
||||
}
|
||||
|
||||
|
||||
Nepomuk::Search::Query::Query( const QString& sparqlQuery )
|
||||
: d ( new Private() )
|
||||
{
|
||||
d->type = SPARQLQuery;
|
||||
d->sparqlQuery = sparqlQuery;
|
||||
}
|
||||
|
||||
|
||||
Nepomuk::Search::Query::~Query()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Nepomuk::Search::Query& Nepomuk::Search::Query::operator=( const Query& other )
|
||||
{
|
||||
d = other.d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Nepomuk::Search::Query::Type Nepomuk::Search::Query::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
|
||||
Nepomuk::Search::Term Nepomuk::Search::Query::term() const
|
||||
{
|
||||
return d->term;
|
||||
}
|
||||
|
||||
|
||||
int Nepomuk::Search::Query::limit() const
|
||||
{
|
||||
return d->limit;
|
||||
}
|
||||
|
||||
|
||||
QString Nepomuk::Search::Query::sparqlQuery() const
|
||||
{
|
||||
return d->sparqlQuery;
|
||||
}
|
||||
|
||||
|
||||
void Nepomuk::Search::Query::setTerm( const Term& term )
|
||||
{
|
||||
d->term = term;
|
||||
d->type = PlainQuery;
|
||||
}
|
||||
|
||||
|
||||
void Nepomuk::Search::Query::setLimit( int limit )
|
||||
{
|
||||
d->limit = limit;
|
||||
}
|
||||
|
||||
|
||||
void Nepomuk::Search::Query::setSparqlQuery( const QString& qs )
|
||||
{
|
||||
d->sparqlQuery = qs;
|
||||
d->term = Term();
|
||||
d->type = SPARQLQuery;
|
||||
}
|
||||
|
||||
|
||||
void Nepomuk::Search::Query::addRequestProperty( const QUrl& property, bool optional )
|
||||
{
|
||||
d->requestProperties.append( qMakePair( property, optional ) );
|
||||
}
|
||||
|
||||
|
||||
void Nepomuk::Search::Query::clearRequestProperties()
|
||||
{
|
||||
d->requestProperties.clear();
|
||||
}
|
||||
|
||||
|
||||
QList<Nepomuk::Search::Query::RequestProperty> Nepomuk::Search::Query::requestProperties() const
|
||||
{
|
||||
return d->requestProperties;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
bool compareRequestProperties( const QList<Nepomuk::Search::Query::RequestProperty>& rp1, const QList<Nepomuk::Search::Query::RequestProperty>& rp2 ) {
|
||||
// brute force
|
||||
foreach( const Nepomuk::Search::Query::RequestProperty& rp, rp1 ) {
|
||||
if ( !rp2.contains( rp ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
foreach( const Nepomuk::Search::Query::RequestProperty& rp, rp2 ) {
|
||||
if ( !rp1.contains( rp ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Nepomuk::Search::Query::operator==( const Query& other ) const
|
||||
{
|
||||
if ( d->type == other.d->type &&
|
||||
d->limit == other.d->limit ) {
|
||||
if ( d->type == SPARQLQuery ) {
|
||||
return( d->sparqlQuery == other.d->sparqlQuery &&
|
||||
compareRequestProperties( d->requestProperties, other.d->requestProperties ) );
|
||||
}
|
||||
else {
|
||||
return( d->term == other.d->term &&
|
||||
compareRequestProperties( d->requestProperties, other.d->requestProperties ) );
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
QDebug operator<<( QDebug dbg, const Nepomuk::Search::Query& query )
|
||||
{
|
||||
dbg << "(Query" << query.term() << query.limit() << ")";
|
||||
return dbg;
|
||||
}
|
||||
|
||||
|
||||
uint Nepomuk::Search::qHash( const Nepomuk::Search::Query& query )
|
||||
{
|
||||
if ( query.type() == Nepomuk::Search::Query::SPARQLQuery )
|
||||
return qHash( query.sparqlQuery() );
|
||||
else
|
||||
return qHash( query.term() );
|
||||
}
|
122
nepomukquery/query.h
Normal file
122
nepomukquery/query.h
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
This file is part of the Nepomuk KDE project.
|
||||
Copyright (C) 2008 Sebastian Trueg <trueg@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2 as published by the Free Software Foundation.
|
||||
|
||||
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 _NEPOMUK_SEARCH_QUERY_H_
|
||||
#define _NEPOMUK_SEARCH_QUERY_H_
|
||||
|
||||
#include <QtCore/QSharedDataPointer>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QPair>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "nepomukquery_export.h"
|
||||
|
||||
class QUrl;
|
||||
|
||||
namespace Nepomuk {
|
||||
namespace Search {
|
||||
|
||||
class Term;
|
||||
|
||||
/**
|
||||
* \class Query query.h nepomuk/query.h
|
||||
*
|
||||
* \brief A Nepomuk desktop query.
|
||||
*
|
||||
* A query can either be based on Term or a more complex
|
||||
* SPARQL query.
|
||||
*
|
||||
* \author Sebastian Trueg <trueg@kde.org>
|
||||
*/
|
||||
class NEPOMUKQUERY_EXPORT Query
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
InvalidQuery,
|
||||
PlainQuery,
|
||||
SPARQLQuery
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an empty invalid query object.
|
||||
*/
|
||||
Query();
|
||||
|
||||
/**
|
||||
* Create a query of type PlainQuery based on
|
||||
* \a term.
|
||||
*/
|
||||
Query( const Term& term );
|
||||
|
||||
/**
|
||||
* Create a SPARQL query. The query has to have one select variable called "?r"
|
||||
*/
|
||||
explicit Query( const QString& sparqlQuery );
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*/
|
||||
Query( const Query& );
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Query();
|
||||
|
||||
/**
|
||||
* Assignment operator
|
||||
*/
|
||||
Query& operator=( const Query& );
|
||||
|
||||
Type type() const;
|
||||
Term term() const;
|
||||
QString sparqlQuery() const;
|
||||
int limit() const;
|
||||
|
||||
void setTerm( const Term& );
|
||||
void setSparqlQuery( const QString& );
|
||||
void setLimit( int );
|
||||
|
||||
/**
|
||||
* Add a property that should be reported with each search result.
|
||||
* \param property The requested property.
|
||||
* \param optional If \p true the property is optional, meaning it can
|
||||
* be empty ins earch results.
|
||||
*/
|
||||
void addRequestProperty( const QUrl& property, bool optional = true );
|
||||
void clearRequestProperties();
|
||||
|
||||
typedef QPair<QUrl, bool> RequestProperty;
|
||||
|
||||
QList<RequestProperty> requestProperties() const;
|
||||
|
||||
bool operator==( const Query& ) const;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QSharedDataPointer<Private> d;
|
||||
};
|
||||
|
||||
NEPOMUKQUERY_EXPORT uint qHash( const Nepomuk::Search::Query& );
|
||||
}
|
||||
}
|
||||
|
||||
NEPOMUKQUERY_EXPORT QDebug operator<<( QDebug, const Nepomuk::Search::Query& );
|
||||
|
||||
#endif
|
279
nepomukquery/queryparser.cpp
Normal file
279
nepomukquery/queryparser.cpp
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
This file is part of the Nepomuk KDE project.
|
||||
Copyright (C) 2007 Sebastian Trueg <trueg@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2 as published by the Free Software Foundation.
|
||||
|
||||
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 "queryparser.h"
|
||||
#include "query.h"
|
||||
#include "term.h"
|
||||
|
||||
#include <QtCore/QRegExp>
|
||||
#include <QtCore/QSet>
|
||||
|
||||
#include <KDebug>
|
||||
#include <KLocale>
|
||||
|
||||
|
||||
/* Advanced queries:
|
||||
* select distinct ?r ?p ?x ?label ?comment where { { ?r ?p ?x . } UNION { ?r ?p ?r2 . ?r2 ?p2 ?x . } . FILTER(isLiteral(?x)) . FILTER REGEX(STR(?p),'hastag','i') . FILTER REGEX(STR(?x),'nepomuk','i') . OPTIONAL { { ?r <http://www.w3.org/2000/01/rdf-schema#label> ?label } UNION { ?r <http://www.semanticdesktop.org/ontologies/2007/08/15/nao#prefLabel> ?label . } UNION { ?r <http://freedesktop.org/standards/xesam/1.0/core#name> ?label . } . ?r <http://www.w3.org/2000/01/rdf-schema#comment> ?comment . } . }
|
||||
*/
|
||||
|
||||
namespace {
|
||||
// a field differs from a plain term in that it does never allow comparators
|
||||
QString s_fieldNamePattern( "([^\\s\"':=<>]+|(?:([\"'])[^\"':=<>]+\\%1))" );
|
||||
QString s_plainTermPattern( "([^\\s\"':=<>]+|(?:([\"'])[^\"']+\\%1))" );
|
||||
QString s_inExclusionPattern( "([\\+\\-]?)" );
|
||||
QString s_uriPattern( "<([^<>]+)>" );
|
||||
QString s_comparatorPattern( "(:|\\<=|\\>=|=|\\<|\\>)" );
|
||||
|
||||
// match a simple search text
|
||||
// captures: 1 - The optional + or - sign (may be empty)
|
||||
// 2 - the search text (including optional paranthesis)
|
||||
QRegExp s_plainTermRx( s_inExclusionPattern + s_plainTermPattern.arg( 3 ) );
|
||||
|
||||
// match a field search term: fieldname + relation (:, =, etc) + search text with optional paranthesis
|
||||
// captures: 1 - The optional + or - sign (may be empty)
|
||||
// 2 - fieldname
|
||||
// 3 - relation
|
||||
// 4 - search text (including optional paranthesis)
|
||||
QRegExp s_fieldRx( s_inExclusionPattern + s_fieldNamePattern.arg( 3 ) + s_comparatorPattern + s_plainTermPattern.arg( 6 ) );
|
||||
|
||||
// match a property URI search term: property URI + relation (:, =, etc) + search text with optional paranthesis
|
||||
// captures: 1 - The optional + or - sign (may be empty)
|
||||
// 2 - property URI
|
||||
// 3 - relation
|
||||
// 4 - search text (including optional paranthesis)
|
||||
QRegExp s_propertyRx( s_inExclusionPattern + s_uriPattern + s_comparatorPattern + s_plainTermPattern.arg( 5 ) );
|
||||
|
||||
// match a property URI search term: property URI + relation (:, =, etc) + resource URI
|
||||
// captures: 1 - The optional + or - sign (may be empty)
|
||||
// 2 - property URI
|
||||
// 3 - resource URI
|
||||
QRegExp s_resourceRx( s_inExclusionPattern + s_uriPattern + "(?::|=)" + s_uriPattern );
|
||||
|
||||
QRegExp s_fieldFieldRx( s_inExclusionPattern + s_fieldNamePattern.arg( 3 ) + s_comparatorPattern + "\\(" + s_fieldNamePattern.arg( 6 ) + s_comparatorPattern + s_plainTermPattern.arg( 9 ) + "\\)" );
|
||||
|
||||
Nepomuk::Search::Term::Comparator fieldTypeRelationFromString( const QString& s ) {
|
||||
if ( s == "=" ) {
|
||||
return Nepomuk::Search::Term::Equal;
|
||||
}
|
||||
else if ( s == ":" ) {
|
||||
return Nepomuk::Search::Term::Contains;
|
||||
}
|
||||
else if ( s == ">" ) {
|
||||
return Nepomuk::Search::Term::Greater;
|
||||
}
|
||||
else if ( s == "<" ) {
|
||||
return Nepomuk::Search::Term::Smaller;
|
||||
}
|
||||
else if ( s == ">=" ) {
|
||||
return Nepomuk::Search::Term::GreaterOrEqual;
|
||||
}
|
||||
else if ( s == "<=" ) {
|
||||
return Nepomuk::Search::Term::SmallerOrEqual;
|
||||
}
|
||||
else {
|
||||
kDebug() << "FIXME: Unsupported relation:" << s;
|
||||
return Nepomuk::Search::Term::Equal;
|
||||
}
|
||||
}
|
||||
|
||||
QString stripQuotes( const QString& s ) {
|
||||
if ( s[0] == '\'' ||
|
||||
s[0] == '\"' ) {
|
||||
return s.mid( 1 ).left( s.length()-2 );
|
||||
}
|
||||
else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
QUrl tryToBeIntelligentAboutParsingUrl( const QString& s ) {
|
||||
if ( s.contains( '%' ) && !s.contains( '/' ) ) {
|
||||
return QUrl::fromEncoded( s.toAscii() );
|
||||
}
|
||||
else {
|
||||
return QUrl( s );
|
||||
}
|
||||
}
|
||||
|
||||
Soprano::LiteralValue createLiteral( const QString& s ) {
|
||||
bool b = false;
|
||||
int i = s.toInt( &b );
|
||||
if ( b )
|
||||
return Soprano::LiteralValue( i );
|
||||
double d = s.toDouble( &b );
|
||||
if ( b )
|
||||
return Soprano::LiteralValue( d );
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Nepomuk::Search::Query Nepomuk::Search::QueryParser::parseQuery( const QString& query )
|
||||
{
|
||||
QueryParser parser;
|
||||
return parser.parse( query );
|
||||
}
|
||||
|
||||
|
||||
class Nepomuk::Search::QueryParser::Private
|
||||
{
|
||||
public:
|
||||
QSet<QString> andKeywords;
|
||||
QSet<QString> orKeywords;
|
||||
};
|
||||
|
||||
|
||||
Nepomuk::Search::QueryParser::QueryParser()
|
||||
: d( new Private() )
|
||||
{
|
||||
QString andListStr = i18nc( "Boolean AND keyword in desktop search strings. You can add several variants separated by spaces, e.g. retain the English one alongside the translation; keywords are not case sensitive. Make sure there is no conflict with the OR keyword.", "and" );
|
||||
foreach ( const QString &andKeyword, andListStr.split( " ", QString::SkipEmptyParts ) ) {
|
||||
d->andKeywords.insert( andKeyword.toLower() );
|
||||
}
|
||||
QString orListStr = i18nc( "Boolean OR keyword in desktop search strings. You can add several variants separated by spaces, e.g. retain the English one alongside the translation; keywords are not case sensitive. Make sure there is no conflict with the AND keyword.", "or" );
|
||||
foreach ( const QString &orKeyword, orListStr.split( " ", QString::SkipEmptyParts ) ) {
|
||||
d->orKeywords.insert( orKeyword.toLower() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Nepomuk::Search::QueryParser::~QueryParser()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
|
||||
Nepomuk::Search::Query Nepomuk::Search::QueryParser::parse( const QString& query )
|
||||
{
|
||||
// TODO: a "real" parser which can handle all of the Xesam user language
|
||||
// This one for example does not handle nesting at all.
|
||||
|
||||
QList<Term> terms;
|
||||
|
||||
bool inOrBlock = false;
|
||||
bool inAndBlock = false;
|
||||
|
||||
int pos = 0;
|
||||
while ( pos < query.length() ) {
|
||||
// skip whitespace
|
||||
while ( pos < query.length() && query[pos].isSpace() ) {
|
||||
kDebug() << "Skipping space at" << pos;
|
||||
++pos;
|
||||
}
|
||||
|
||||
Term term;
|
||||
|
||||
if ( pos < query.length() ) {
|
||||
if ( s_resourceRx.indexIn( query, pos ) == pos ) {
|
||||
// FIXME: honour the +-
|
||||
kDebug() << "matched resource term at" << pos << s_resourceRx.cap( 0 );
|
||||
term = Term( tryToBeIntelligentAboutParsingUrl( s_resourceRx.cap( 2 ) ),
|
||||
tryToBeIntelligentAboutParsingUrl( s_resourceRx.cap( 3 ) ) );
|
||||
pos += s_resourceRx.matchedLength();
|
||||
}
|
||||
else if ( s_propertyRx.indexIn( query, pos ) == pos ) {
|
||||
// FIXME: honour the +-
|
||||
kDebug() << "matched property term at" << pos << s_propertyRx.cap( 0 );
|
||||
term.setProperty( tryToBeIntelligentAboutParsingUrl( s_propertyRx.cap( 2 ) ) );
|
||||
term.addSubTerm( Term( createLiteral( stripQuotes( s_propertyRx.cap( 4 ) ) ) ) );
|
||||
QString comparator = s_propertyRx.cap( 3 );
|
||||
term.setType( Term::ComparisonTerm );
|
||||
term.setComparator( fieldTypeRelationFromString( comparator ) );
|
||||
pos += s_propertyRx.matchedLength();
|
||||
}
|
||||
else if ( s_fieldFieldRx.indexIn( query, pos ) == pos ) {
|
||||
kDebug() << "matched field field term at" << pos
|
||||
<< s_fieldFieldRx.cap( 0 )
|
||||
<< s_fieldFieldRx.cap( 2 )
|
||||
<< s_fieldFieldRx.cap( 4 )
|
||||
<< s_fieldFieldRx.cap( 5 )
|
||||
<< s_fieldFieldRx.cap( 7 )
|
||||
<< s_fieldFieldRx.cap( 8 );
|
||||
term.setField( stripQuotes( s_fieldFieldRx.cap( 2 ) ) );
|
||||
QString comparator = s_fieldFieldRx.cap( 4 );
|
||||
term.setType( Term::ComparisonTerm );
|
||||
term.setComparator( fieldTypeRelationFromString( comparator ) );
|
||||
term.addSubTerm( Term( stripQuotes( s_fieldFieldRx.cap( 5 ) ), s_fieldFieldRx.cap( 8 ), fieldTypeRelationFromString( s_fieldFieldRx.cap( 7 ) ) ) );
|
||||
pos += s_fieldFieldRx.matchedLength();
|
||||
}
|
||||
else if ( s_fieldRx.indexIn( query, pos ) == pos ) {
|
||||
// FIXME: honour the +-
|
||||
kDebug() << "matched field term at" << pos << s_fieldRx.cap( 0 ) << s_fieldRx.cap( 2 ) << s_fieldRx.cap( 4 ) << s_fieldRx.cap( 5 );
|
||||
term.setField( stripQuotes( s_fieldRx.cap( 2 ) ) );
|
||||
term.addSubTerm( Term( createLiteral( stripQuotes( s_fieldRx.cap( 5 ) ) ) ) );
|
||||
QString comparator = s_fieldRx.cap( 4 );
|
||||
term.setType( Term::ComparisonTerm );
|
||||
term.setComparator( fieldTypeRelationFromString( comparator ) );
|
||||
pos += s_fieldRx.matchedLength();
|
||||
}
|
||||
else if ( s_plainTermRx.indexIn( query, pos ) == pos ) {
|
||||
// FIXME: honour the +-
|
||||
QString value = stripQuotes( s_plainTermRx.cap( 2 ) );
|
||||
if ( d->orKeywords.contains( value.toLower() ) ) {
|
||||
inOrBlock = true;
|
||||
}
|
||||
else if ( d->andKeywords.contains( value.toLower() ) ) {
|
||||
inAndBlock = true;
|
||||
}
|
||||
else {
|
||||
kDebug() << "matched literal at" << pos << value;
|
||||
term = Term( Soprano::LiteralValue( value ) );
|
||||
}
|
||||
pos += s_plainTermRx.matchedLength();
|
||||
}
|
||||
else {
|
||||
kDebug() << "Invalid query at" << pos << query;
|
||||
return Term();
|
||||
}
|
||||
|
||||
if ( term.isValid() ) {
|
||||
if ( inOrBlock && !terms.isEmpty() ) {
|
||||
Term orTerm;
|
||||
orTerm.setType( Term::OrTerm );
|
||||
orTerm.addSubTerm( terms.takeLast() );
|
||||
orTerm.addSubTerm( term );
|
||||
terms.append( orTerm );
|
||||
}
|
||||
else if ( inAndBlock && !terms.isEmpty() ) {
|
||||
Term andTerm;
|
||||
andTerm.setType( Term::AndTerm );
|
||||
andTerm.addSubTerm( terms.takeLast() );
|
||||
andTerm.addSubTerm( term );
|
||||
terms.append( andTerm );
|
||||
}
|
||||
else {
|
||||
terms.append( term );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( terms.count() == 1 ) {
|
||||
return terms[0];
|
||||
}
|
||||
else if ( terms.count() > 0 ) {
|
||||
Term t;
|
||||
t.setType( Term::AndTerm );
|
||||
t.setSubTerms( terms );
|
||||
return t;
|
||||
}
|
||||
else {
|
||||
return Term();
|
||||
}
|
||||
}
|
49
nepomukquery/queryparser.h
Normal file
49
nepomukquery/queryparser.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
This file is part of the Nepomuk KDE project.
|
||||
Copyright (C) 2007 Sebastian Trueg <trueg@kde.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License version 2 as published by the Free Software Foundation.
|
||||
|
||||
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 _NEPOMUK_SEARCH_QUERY_PARSER_H_
|
||||
#define _NEPOMUK_SEARCH_QUERY_PARSER_H_
|
||||
|
||||
#include "query.h"
|
||||
|
||||
#include <QtCore/QString>
|
||||
|
||||
#include "nepomukquery_export.h"
|
||||
|
||||
|
||||
namespace Nepomuk {
|
||||
namespace Search {
|
||||
class NEPOMUKQUERY_EXPORT QueryParser
|
||||
{
|
||||
public:
|
||||
QueryParser();
|
||||
~QueryParser();
|
||||
|
||||
Query parse( const QString& query );
|
||||
|
||||
static Query parseQuery( const QString& query );
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private* const d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user