diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 4aed2c8219774f5d797760606b8489a92ddc5163 (patch) | |
tree | 3f8c130f7d269626bf6a9447407ef6c35954426a /ksysguard | |
download | tdebase-4aed2c8219774f5d797760606b8489a92ddc5163.tar.gz tdebase-4aed2c8219774f5d797760606b8489a92ddc5163.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'ksysguard')
224 files changed, 34725 insertions, 0 deletions
diff --git a/ksysguard/CContLib/Makefile.am b/ksysguard/CContLib/Makefile.am new file mode 100644 index 000000000..a3f5d786d --- /dev/null +++ b/ksysguard/CContLib/Makefile.am @@ -0,0 +1,6 @@ +AUTOMAKE_OPTIONS = foreign + +noinst_LIBRARIES = libccont.a +noinst_HEADERS = ccont.h + +libccont_a_SOURCES = ccont.c diff --git a/ksysguard/CContLib/ccont.c b/ksysguard/CContLib/ccont.c new file mode 100644 index 000000000..501429337 --- /dev/null +++ b/ksysguard/CContLib/ccont.c @@ -0,0 +1,364 @@ +/* + Lightweight C Container Library + + Copyright (c) 2002 Tobias Koenig <tokoe@kde.org> + + Original code was written by Chris Schlaeger <cs@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 "ccont.h" + +#include <stdio.h> +#include <stdlib.h> + +struct container_info { + INDEX count; + CONTAINER currentNode; +}; + +typedef struct container_info T_CONTAINER_INFO; +typedef struct container_info* CONTAINER_INFO; + +#define rpterr(x) fprintf(stderr, "%s\n", x) + +CONTAINER new_ctnr(void) +{ + CONTAINER_INFO info; + CONTAINER rootNode; + + rootNode = (CONTAINER)malloc(sizeof(T_CONTAINER)); + + info = (CONTAINER_INFO)malloc(sizeof(T_CONTAINER_INFO)); + info->count = 0; + info->currentNode = rootNode; + + rootNode->next = rootNode; + rootNode->prev = rootNode; + rootNode->data = info; + + return rootNode; +} + +void zero_destr_ctnr(CONTAINER rootNode, DESTR_FUNC destr_func) +{ + INDEX counter; + + if (rootNode == NIL || destr_func == NIL) { + rpterr("destr_ctnr: NIL argument"); + return; + } + + for (counter = level_ctnr(rootNode); counter > -1; --counter) + destr_func(pop_ctnr(rootNode)); + + if (rootNode->data) + free(rootNode->data); + + free(rootNode); + rootNode = 0; + + return; +} + +INDEX level_ctnr(CONTAINER rootNode) +{ + if (rootNode == NIL) { + rpterr("level_ctnr: NIL argument"); + return -1; + } + + return ((CONTAINER_INFO)rootNode->data)->count; +} + +void insert_ctnr(CONTAINER rootNode, void* object, INDEX pos) +{ + CONTAINER it; + INDEX counter = 0; + + if (rootNode == NIL || object == NIL) { + rpterr("insert_ctnr: NIL argument"); + return; + } + + for (it = rootNode->next; it != rootNode; it = it->next) { + if (counter == pos) { + CONTAINER newNode = (CONTAINER)malloc(sizeof(T_CONTAINER)); + + newNode->prev = it; + newNode->next = it->next; + it->next->prev = newNode; + it->next = newNode; + + newNode->data = object; + ((CONTAINER_INFO)rootNode->data)->count++; + return; + } + + counter++; + } +} + +void push_ctnr(CONTAINER rootNode, void* object) +{ + CONTAINER newNode; + + if (rootNode == NIL || object == NIL) { + rpterr("push_ctnr: NIL argument"); + return; + } + + newNode = (CONTAINER)malloc(sizeof(T_CONTAINER)); + newNode->next = rootNode; + newNode->prev = rootNode->prev; + rootNode->prev->next = newNode; + rootNode->prev = newNode; + + newNode->data = object; + ((CONTAINER_INFO)rootNode->data)->count++; +} + +void* remove_at_ctnr(CONTAINER rootNode, INDEX pos) +{ + CONTAINER it; + INDEX counter = 0; + void* retval; + + if (rootNode == NIL) { + rpterr("remove_ctnr: NIL argument"); + return NIL; + } + + for (it = rootNode->next; it != rootNode; it = it->next) { + if (counter == pos) { + retval = it->data; + + it->prev->next = it->next; + it->next->prev = it->prev; + + free(it); + + ((CONTAINER_INFO)rootNode->data)->count--; + return retval; + } + + counter++; + } + + return NIL; +} + +void* pop_ctnr(CONTAINER rootNode) +{ + CONTAINER ptr; + void* retval; + + if (rootNode == NIL) { + rpterr("pop_ctnr: NIL argument"); + return NIL; + } + + if (rootNode->next == rootNode) + return NIL; + + ptr = rootNode->next; + retval = ptr->data; + + rootNode->next = ptr->next; + ptr->next->prev = rootNode; + + ((CONTAINER_INFO)rootNode->data)->count--; + + free(ptr); + + return retval; +} + +void* get_ctnr(CONTAINER rootNode, INDEX pos) +{ + CONTAINER it; + INDEX counter = 0; + + if (rootNode == NIL) { + rpterr("get_ctnr: NIL argument"); + return NIL; + } + + for (it = rootNode->next; it != rootNode; it = it->next) { + if (counter == pos) + return it->data; + + counter++; + } + + return NIL; +} + +INDEX search_ctnr(CONTAINER rootNode, COMPARE_FUNC compare_func, void* pattern) +{ + CONTAINER it; + INDEX counter = 0; + + if (rootNode == NIL || compare_func == NIL || pattern == NIL) { + rpterr("search_ctnr: NIL argument"); + return -1; + } + + for (it = rootNode->next; it != rootNode; it = it->next) { + if (compare_func(pattern, it->data) == 0) + return counter; + + counter++; + } + + return -1; +} + +void swop_ctnr(CONTAINER rootNode, INDEX pos1, INDEX pos2) +{ + CONTAINER it, node1, node2; + INDEX counter = 0; + int found = 0; + void* tmpData; + + if (rootNode == NIL) { + rpterr("swop_ctnr: NIL argument"); + return; + } + + if (pos1 == pos2) + return; + + /** + * it is a bit hackish because of the 'goto' but it's fast + * since we have to run through the list only once + */ + for (it = rootNode->next; it != rootNode; it = it->next) { + if (counter == pos1) { + node1 = it; + if (found) + goto swapIt; + else + found = 1; + } + if (counter == pos2) { + node2 = it; + if (found) + goto swapIt; + else + found = 1; + } + + counter++; + } + + return; + +swapIt: + tmpData = node1->data; + node1->data = node2->data; + node2->data = tmpData; + return; +} + +void bsort_ctnr(CONTAINER rootNode, COMPARE_FUNC compare_func) +{ + INDEX right, i, level, last; + + if (rootNode == NIL || compare_func == NIL) { + rpterr("destr_ctnr: NIL argument"); + return; + } + + last = level = level_ctnr(rootNode); + do + { + right = last; + last = 0; + for (i = 1; i < right; i++) + if (compare_func(get_ctnr(rootNode, i - 1), get_ctnr(rootNode, i)) > 0) + swop_ctnr(rootNode, i - 1, last = i); + } while (last > 0); +} + +void* first_ctnr(CONTAINER rootNode) +{ + if (rootNode == NIL) { + rpterr("first_ctnr: NIL argument"); + return NIL; + } + + if (rootNode->next == rootNode) + return NIL; + + ((CONTAINER_INFO)rootNode->data)->currentNode = rootNode->next; + + return rootNode->next->data; +} + +void* next_ctnr(CONTAINER rootNode) +{ + CONTAINER_INFO info; + + if (rootNode == NIL) { + rpterr("next_ctnr: NIL argument"); + return NIL; + } + + info = (CONTAINER_INFO)rootNode->data; + + if (info->currentNode->next == rootNode) + return NIL; + + info->currentNode = info->currentNode->next; + + return info->currentNode->data; +} + +void* remove_ctnr(CONTAINER rootNode) +{ + CONTAINER currentNode, tmp; + CONTAINER_INFO info; + void* retval; + + if (rootNode == NIL) { + rpterr("remove_curr_ctnr: NIL argument"); + return NIL; + } + + info = (CONTAINER_INFO)rootNode->data; + currentNode = info->currentNode; + + if (currentNode == rootNode) { /* should never happen */ + rpterr("remove_curr_ctnr: delete root node"); + return NIL; + } + + retval = currentNode->data; + tmp = currentNode->prev; + + currentNode->prev->next = currentNode->next; + currentNode->next->prev = currentNode->prev; + + free(currentNode); + + info->count--; + info->currentNode = tmp; + + return retval; +} diff --git a/ksysguard/CContLib/ccont.h b/ksysguard/CContLib/ccont.h new file mode 100644 index 000000000..66b22eba4 --- /dev/null +++ b/ksysguard/CContLib/ccont.h @@ -0,0 +1,161 @@ +/* + Lightweight C Container Library + + Copyright (c) 2002 Tobias Koenig <tokoe@kde.org> + + Original code was written by Chris Schlaeger <cs@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 _CCONT_H +#define _CCONT_H + +#ifndef NIL +#define NIL ((void*) 0) +#endif + +#define destr_ctnr(x, y) zero_destr_ctnr(x, y); x=0 + +struct container { + struct container* next; + struct container* prev; + void* data; +}; + +typedef struct container T_CONTAINER; +typedef struct container* CONTAINER; + +typedef long INDEX; + +typedef void (*DESTR_FUNC)(void*); +typedef int (*COMPARE_FUNC)(void*, void*); + +/** + * Initialize the container @p ctnr. + */ +CONTAINER new_ctnr(void); + +/** + * Remove all entries from @p ctnr and reset its + * internal structure. Use @ref new_ctnr() @em before @em + * access the container next time. + * + * Note: use the 'destr_ctnr' macro to get zeroed pointer + * automatically. + * + * @param destr_func The function that is called to + * free the single entries. + */ +void zero_destr_ctnr(CONTAINER ctnr, DESTR_FUNC destr_func); + +/** + * @return the number of entries in @p ctnr. + */ +INDEX level_ctnr(CONTAINER ctnr); + +/** + * Insert a new entry in container. + * + * @param object A pointer to the object. + * @param pos The position where the object should be insert. + */ +void insert_ctnr(CONTAINER ctnr, void* object, INDEX pos); + +/** + * Add a new entry at the end of container. + * + * @param object The object that should be added. + */ +void push_ctnr(CONTAINER ctnr, void* object); + +/** + * Remove an entry from container. + * + * @param pos The position of the object that should be removed. + * + * @return A pointer to the removed object or @p 0L if it doesn't exist. + */ +void* remove_at_ctnr(CONTAINER ctnr, INDEX pos); + +/** + * Remove the first entry of container. + * + * @return A pointer to the removed object or @p 0L if there is now entry. + */ +void* pop_ctnr(CONTAINER ctnr); + +/** + * @return A pointer to the object at position @a pos + * or @p 0L if it doesn't exist. + */ +void* get_ctnr(CONTAINER ctnr, INDEX pos); + +/** + * @return The position of a matching entry. + * + * @param compare_func A Pointer to the function that is + * called to compare all entries in the + * container with the given pattern. + * @param pattern The pattern for coparison. + */ +INDEX search_ctnr(CONTAINER ctnr, COMPARE_FUNC compare_func, void* pattern); + +/** + * Swap two objects in container. + * + * @param pos1 Position of the first object. + * @param pos2 Position of the second object. + */ +void swop_ctnr(CONTAINER ctnr, INDEX pos1, INDEX pos2); + +/** + * Sort all entries of container. + * + * @param compare_func A Pointer to the function that is + * called to compare to entries of the + * container. + */ +void bsort_ctnr(CONTAINER ctnr, COMPARE_FUNC compare_func); + +/** + * Use this function to iterate over the container. + * + * for (ptr = first_ctnr(ctnr); ptr; ptr = next_ctnr(ctnr)) { + * do_anything(ptr); + * } + * + * @return A Pointer to the first object in container. + */ +void* first_ctnr(CONTAINER ctnr); + +/** + * Use this function to iterate over the container. + * + * @return A Pointer to the next object in container. + */ +void* next_ctnr(CONTAINER ctnr); + +/** + * Use this function to remove the current entry while + * iterating over the container. + * + * @return A Pointer to the removed object or @p 0L if it doesn't exist. + */ +void* remove_ctnr(CONTAINER ctnr); + +#endif diff --git a/ksysguard/Makefile.am b/ksysguard/Makefile.am new file mode 100644 index 000000000..4d4223b60 --- /dev/null +++ b/ksysguard/Makefile.am @@ -0,0 +1,9 @@ +if include_ksysguardd +KSYSGUARDD_DIR = ksysguardd +endif + +# claim, which subdirectories you want to install +SUBDIRS = CContLib $(KSYSGUARDD_DIR) gui pics example + +KDE_ICON = ksysguard + diff --git a/ksysguard/Makefile.in.temp b/ksysguard/Makefile.in.temp new file mode 100644 index 000000000..b8e021dc2 --- /dev/null +++ b/ksysguard/Makefile.in.temp @@ -0,0 +1,99 @@ + +# the most documentation you find in Makefile.am +# this file is just to demonstrate, how complex it is to +# write good Makefiles, if you don't use automake ;) + +# export the variables, we're using +prefix = @prefix@ +exec_prefix = @exec_prefix@ +top_srcdir = @top_srcdir@ +kde_appsdir = @kde_appsdir@ +kde_cgidir = @kde_cgidir@ +kde_confdir = @kde_confdir@ +kde_datadir = @kde_datadir@ +kde_htmldir = @kde_htmldir@ +kde_icondir = @kde_icondir@ +kde_locale = @kde_locale@ +kde_mimedir = @kde_mimedir@ +kde_minidir = @kde_minidir@ +kde_toolbardir = @kde_toolbardir@ +kde_wallpaperdir= @kde_wallpaperdir@ +bindir = @bindir@ + +all_includes = @all_includes@ +all_libraries = @all_libraries@ + +MOC = @MOC@ +XGETTEXT = @XGETTEXT@ +CXX = @CXX@ +LDFLAGS = @LDFLAGS@ +CXXFLAGS = @CXXFLAGS@ +LIBSOCKET = @LIBSOCKET@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ + +# define some variables +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +APPSDIR = $(kde_appsdir)/Utilities +INCLUDES = $(all_includes) +TARGET = khexdit +LIBS = -lkfm -lkdeui -lkdecore -lqt -lX11 -lXext $(LIBSOCKET) +LDFLAGS += $(all_libraries) + +# rules to make .o files +.SUFFIXES: .cpp +.cpp.o: + $(CXX) $(CXXFLAGS) $(DEFS) $(INCLUDES) -c $< + +OBJECTS = hexfile.o hexwidget.o +SRCMOCS = hexwidget.moc hexfile.moc + +all: $(TARGET) + +$(TARGET): $(SRCMOCS) $(OBJECTS) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) + +# recreate the Makefile +Makefile: Makefile.in + cd .. && CONFIG_FILES=khexdit/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +install: install-data install-exec + +# make messages.po. Move this one to ../po/ and "make merge" in po +messages: + $(XGETTEXT) -C -ktranslate *.cpp + +install-exec: $(TARGET) + $(mkinstalldirs) $(bindir) + $(INSTALL_PROGRAM) $(TARGET) $(bindir) + +install-data: + (cd doc && $(MAKE) install-data) + $(mkinstalldirs) $(APPSDIR) + $(INSTALL_DATA) khexdit.kdelnk $(APPSDIR) + $(mkinstalldirs) $(kde_icondir) + $(INSTALL_DATA) khexdit.xpm $(kde_icondir) + $(mkinstalldirs) $(kde_minidir) + $(INSTALL_DATA) mini-khexdit.xpm $(kde_minidir)/khexdit.xpm + +uninstall: + (cd doc && $(MAKE) uninstall) + -rm -f $(bindir)/$(TARGET) + -rm -f $(APPSDIR)/khexdit.kdelnk + -rm -f $(kde_icondir)/khexdit.xpm + -rm -f $(kde_minidir)/khexdit.xpm + +clean: + -rm -f $(TARGET) $(OBJECTS) *~ core + +distclean: clean + -rm -f Makefile $(SRCMOCS) + +# add a dependcy for all moc files to help some FreeBSD users ;) +hexwidget.moc: hexwidget.h + $(MOC) hexwidget.h -o hexwidget.moc + +hexfile.moc: hexfile.h + $(MOC) hexfile.h -o hexfile.moc diff --git a/ksysguard/README b/ksysguard/README new file mode 100644 index 000000000..36d81e7a3 --- /dev/null +++ b/ksysguard/README @@ -0,0 +1,26 @@ +What is KSysGuard? +------------------ + +KSysGuard, formerly known as KTop is a program to monitor various elements +of your system, or any other remote system with the KSysGuard daemon +(ksysgardd) installed. Currently the daemon has been ported to FreeBSD +and Linux with varying degrees of completion. + +Notes from the author +--------------------- + +KSysGuard, formerly known as KTop is work in progress! Although I only try +to check in reasonably stable versions, I cannot guarantee this. I +typically develop on SuSE Linux 6.x with 2.2 kernel. If your system is +different, this program might not even compile. + +If you want to join this development please contact me first. Please +do *NOT* check in unsolicited code as I might am rearranging the code +and merging becomes a real headache so your code will be lost. + +This does not mean that I don't appreciate your help. Especially +porting to other platforms is difficult for me. Each platform has it's +specific back-end. See the ksysguardd directory for details. + +5-Jan-2000 Chris Schlaeger <cs@kde.org> + diff --git a/ksysguard/configure.in.in b/ksysguard/configure.in.in new file mode 100644 index 000000000..0173b28ea --- /dev/null +++ b/ksysguard/configure.in.in @@ -0,0 +1,50 @@ +dnl Check whether ksysguardd can run; +AC_MSG_CHECKING([if ksysguardd can be compiled]) +case "$host" in + *-*-linux*) ksysguardd_compile=yes; UNAME='Linux' ;; + *-*-freebsd*) ksysguardd_compile=yes; UNAME='FreeBSD' ;; + *-*-dragonfly*) ksysguardd_compile=yes; UNAME='FreeBSD' ;; + *-*-netbsd*) ksysguardd_compile=yes; UNAME='NetBSD' ;; + *-*-solaris*) ksysguardd_compile=yes; UNAME='Solaris' ;; + *-*-osf*) ksysguardd_compile=yes; UNAME='Tru64' ;; + *-*-irix*) ksysguardd_compile=yes; UNAME='Irix' ;; + *-*-openbsd*) ksysguardd_compile=yes; UNAME='OpenBSD' ;; + *) ksysguardd_compile=no; UNAME='' ;; +esac + +AC_MSG_RESULT($ksysguardd_compile) + +AM_CONDITIONAL(include_ksysguardd, test "$ksysguardd_compile" = "yes") +AM_CONDITIONAL(include_ksysguardd_linux, test "$UNAME" = Linux) +AM_CONDITIONAL(include_ksysguardd_freebsd, test "$UNAME" = FreeBSD) +AM_CONDITIONAL(include_ksysguardd_netbsd, test "$UNAME" = NetBSD) +AM_CONDITIONAL(include_ksysguardd_solaris, test "$UNAME" = Solaris) +AM_CONDITIONAL(include_ksysguardd_tru64, test "$UNAME" = Tru64) +AM_CONDITIONAL(include_ksysguardd_irix, test "$UNAME" = Irix) +AM_CONDITIONAL(include_ksysguardd_openbsd, test "$UNAME" = OpenBSD) +AC_SUBST(UNAME) + +AC_ARG_WITH(sensors, + [AC_HELP_STRING(--with-sensors, + [enable support for lm_sensors @<:@default=check@:>@])], + [], with_sensors=check) + +if test "x$with_sensors" != xno; then + KDE_CHECK_HEADERS(sensors/sensors.h) + KDE_CHECK_LIB(sensors, sensors_init, [LIBSENSORS="-lsensors"]) + + if test "x$with_sensors" != xcheck && test -z "$LIBSENSORS"; then + AC_MSG_ERROR([--with-sensors was given, but test for lm_sensors failed]) + fi +fi + +case "$UNAME" in + Linux) LIBHOSTS="$LIBSENSORS" ;; + FreeBSD) LIBHOSTS="$LIBSENSORS -lkvm" ;; + Solaris) LIBHOSTS="$LIBSENSORS -lkstat -lsocket" ;; +esac +AC_SUBST(LIBHOSTS) +AC_SUBST(LIBSENSORS) + +dnl Check for dell laptop support +AM_CONDITIONAL(supports_i8k, test -f /proc/i8k) diff --git a/ksysguard/cr128-app-ksysguard.png b/ksysguard/cr128-app-ksysguard.png Binary files differnew file mode 100644 index 000000000..f2223cde8 --- /dev/null +++ b/ksysguard/cr128-app-ksysguard.png diff --git a/ksysguard/cr16-app-ksysguard.png b/ksysguard/cr16-app-ksysguard.png Binary files differnew file mode 100644 index 000000000..1c2e678da --- /dev/null +++ b/ksysguard/cr16-app-ksysguard.png diff --git a/ksysguard/cr32-app-ksysguard.png b/ksysguard/cr32-app-ksysguard.png Binary files differnew file mode 100644 index 000000000..53005ff57 --- /dev/null +++ b/ksysguard/cr32-app-ksysguard.png diff --git a/ksysguard/cr48-app-ksysguard.png b/ksysguard/cr48-app-ksysguard.png Binary files differnew file mode 100644 index 000000000..b636ff0e6 --- /dev/null +++ b/ksysguard/cr48-app-ksysguard.png diff --git a/ksysguard/cr64-app-ksysguard.png b/ksysguard/cr64-app-ksysguard.png Binary files differnew file mode 100644 index 000000000..95ef34953 --- /dev/null +++ b/ksysguard/cr64-app-ksysguard.png diff --git a/ksysguard/example/Makefile.am b/ksysguard/example/Makefile.am new file mode 100644 index 000000000..67cf43318 --- /dev/null +++ b/ksysguard/example/Makefile.am @@ -0,0 +1,5 @@ +ksysguard_example_datadir = $(kde_datadir)/ksysguard +ksysguard_example_data_DATA = eventsrc + +etcdir = $(sysconfdir) +etc_DATA = ksysguarddrc diff --git a/ksysguard/example/eventsrc b/ksysguard/example/eventsrc new file mode 100644 index 000000000..5051f0cf2 --- /dev/null +++ b/ksysguard/example/eventsrc @@ -0,0 +1,305 @@ +[!Global!] +IconName=ksysguard +Comment=KDE System Guard +Comment[af]=KDE Stelsel Wag +Comment[ar]=حارس النظام KDE +Comment[az]=KDE Sistem Cangüdəni +Comment[be]=Ахоўнік сістэмы KDE +Comment[bg]=Системна защита +Comment[bn]=কে.ডি.ই. সিস্টেম গার্ড +Comment[br]=Gward Reizhiad KDE +Comment[bs]=KDE zaštita sistema +Comment[ca]=Vigilant del sistema KDE +Comment[cs]=Správce systému KDE +Comment[csb]=KDE Wachtôrz Systemë +Comment[cy]=Gwarchodwr Cysawd KDE +Comment[da]=KDE Systemvagt +Comment[de]=KDE-Systemüberwachung +Comment[el]=Φρουρός συστήματος του KDE +Comment[eo]=KDE-Sistemobservilo +Comment[es]=Guardián del sistema de KDE +Comment[et]=KDE süsteemi valvur +Comment[eu]=KDEren sistemaren kontrola +Comment[fa]=محافظ سیستم KDE +Comment[fi]=KDE:n järjestelmänvalvonta +Comment[fr]=Surveillance du système +Comment[fy]=KDE systeembefeiliging +Comment[ga]=Garda an Chórais KDE +Comment[gl]=Vixiante do Sistema de KDE +Comment[he]=משמר המערכת של KDE +Comment[hi]=केडीई तंत्र गार्ड +Comment[hr]=KDE zaštitnik sustava +Comment[hu]=KDE rendszermonitor +Comment[is]=KDE kerfisvörður +Comment[it]=Controllo di sistema di KDE +Comment[ja]=KDE システムガード +Comment[ka]=KDE სისტემური მონიტორი +Comment[kk]=KDE жүйелік бақылаушысы +Comment[km]=ការពារប្រព័ន្ធ KDE +Comment[ko]=KDE 시스템 지킴이 +Comment[lo]=ເຄື່ອງມືຶປ້ອງກັນລະບົບຂອງ KDE +Comment[lt]=KDE sistemos apsauga +Comment[lv]=KDE Sistēmas Sargs +Comment[mk]=KDE Системски чувар +Comment[mn]=КДЭ-Системийн хяналт +Comment[ms]=Pengawas Sistem KDE +Comment[mt]=Gwardja tas-Sistema KDE +Comment[nb]=KDE Systemovervåker +Comment[nds]=KDE-Systeemwachter +Comment[ne]=KDE प्रणाली रक्षक +Comment[nl]=KDE systeembewaking +Comment[nn]=KDE Systemvakt +Comment[nso]=Thlokomelo ya System ya KDE +Comment[pa]=KDE ਸਿਸਟਮ ਗਾਰਡ +Comment[pl]=KDE Strażnik Systemu +Comment[pt]=Vigilante do sistema do KDE +Comment[pt_BR]=Sistema de Guarda do KDE +Comment[ro]=Sistem de gardă KDE +Comment[ru]=Системный монитор +Comment[rw]=Umurinzi Sisitemu KDE +Comment[se]=KDE vuogádatfákta +Comment[sk]=KDE Strážca systému +Comment[sl]=Sistemski varuh KDE +Comment[sr]=KDE чувар система +Comment[sr@Latn]=KDE čuvar sistema +Comment[sv]=KDE:s systemövervakare +Comment[ta]=KDE கணினி காவலன் +Comment[tg]=Муҳофизи системаи KDE +Comment[th]=เครื่องมือป้องกันระบบ KDE +Comment[tr]=KDE Sistem Koruyucu +Comment[tt]=KDE'nıñ Sistem Saqçısı +Comment[uk]=Системний вартовий KDE +Comment[uz]=KDE tizim nazoratchisi +Comment[uz@cyrillic]=KDE тизим назоратчиси +Comment[ven]=Mulindi wa maitele a KDE +Comment[vi]=Trình bảo vệ Hệ thống KDE +Comment[wa]=Gåre sistinme KDE +Comment[xh]=KDE Ukhuselo lendlela yokusebenza +Comment[zh_CN]=KDE 系统卫士 +Comment[zh_TW]=KDE 系統守衛 +Comment[zu]=Unogada Wesistimu ye-KDE + +[pattern_match] +Name=pattern_match +Name[az]=uyğun_naxış +Name[bn]=নকশা_মিল +Name[csb]=dopasowanié_mùstra +Name[cy]=cydweddiad_patrwm +Name[da]=mønster_match +Name[de]=Musterübereinstimmung +Name[eo]=ŝablon_serĉo +Name[es]=concordancia de patrón +Name[fr]=correspondance_avec_motif +Name[gl]=patrón_coincidente +Name[hi]=पैटर्न-मैच +Name[hr]=pronalaženje_uzoraka +Name[hu]=illeszkedő_minta +Name[it]=corrispondenza_schema +Name[ja]=パターンマッチ +Name[km]=លំនាំ ផ្គូផ្គង +Name[ko]=검색 패턴이 일치함 +Name[lo]=ເຂົ້າກັບຮູບແບບ +Name[lt]=šablono atitikimas +Name[lv]=šablona_atbilstība +Name[mk]=совпаѓање_шема +Name[mn]=Загвар-зохицуулга +Name[nb]=mønster_treff +Name[nds]=Musterövereenstimmen +Name[ne]=बाँन्की मिल्दो +Name[nn]=mønster_treff +Name[nso]=tshwanetsano ya mokgwa +Name[pa]=ਪੈਟਰਨ ਮੇਲ +Name[pl]=dopasowanie_wzorca +Name[ro]=potrivire model +Name[rw]=Ishusho_bihura +Name[se]=minsttar_deaivan +Name[sl]=vzorec_zadetek +Name[sr]=подударан_узорак +Name[sr@Latn]=podudaran_uzorak +Name[sv]=mönsterigenkänning +Name[ta]=மாதிரி_பொருத்தம் +Name[ven]=Maitele_Fana +Name[vi]=khớp_mẫu +Name[wa]=va_avou_modele +Name[xh]=umlinganiselo_thelekisa +Name[zh_TW]=比對正確 +Name[zu]=ukufanisa_iphethini +Comment=Search pattern matched +Comment[af]=Soek patroon opgespoor +Comment[ar]=تم ايجاد تماثل +Comment[be]=Пошук супадзенняў з шаблонам +Comment[bg]=Съвпадение на търсения низ +Comment[bn]=সন্ধান করা প্যাটার্ন-এর মিল পাওয়া গেছে +Comment[bs]=Pronađen uzorak za pretragu +Comment[ca]=Cerca coincidència de patró +Comment[cs]=Hledaný vzor odpovídá +Comment[csb]=Mùster òstôł dopasowóny +Comment[da]=Søgemønsteret matchede +Comment[de]=Übereinstimmung mit Suchmuster +Comment[el]=Ταίριασμα μοτίβου αναζήτησης +Comment[eo]=Serĉoŝablonesprimo kongruas +Comment[es]=Coincidencia con el patrón de búsqueda +Comment[et]=Otsingu muster sobib +Comment[eu]=bilatutako eredua bat dator +Comment[fa]=جستجوی الگوی تطبیقشده +Comment[fi]=Hakumerkkijono osui +Comment[fr]=Motif de recherche trouvé +Comment[fy]=Sykpatroan komt oerien +Comment[gl]=o patrón a procurar atopou-se +Comment[he]=נמצאה התאמה לדפוס החיפוש +Comment[hi]=सर्च पैटर्न मेल खाते हैं +Comment[hr]=Traženi je uzorak pronađen +Comment[hu]=Illeszkedő keresési minta +Comment[is]=finna skv. leitarmynstri +Comment[it]=Schema di ricerca trovato +Comment[ja]=検索パターンにマッチしました +Comment[ka]=ძიების ნიმუშთან შესაბამისობა +Comment[kk]=Ізделген үлгіге сәйкестік +Comment[km]=លំនាំស្វែងរកបានផ្គូផ្គង +Comment[ko]=검색 패턴이 일치함 +Comment[lt]=Paieškos šablonas atitiko +Comment[lv]=Meklēšanas šablons atbilst +Comment[mk]=Пребарувањето се поклопува +Comment[ms]=Cari corak sepadan +Comment[mt]=skema ta' tfittxija qablet +Comment[nb]=Søkemønsteret passet +Comment[nds]=Söökmuster passt +Comment[ne]=बाँन्की मिल्दो खोजी गर्नुहोस् +Comment[nl]=Zoekpatroon komt overeen +Comment[nn]=Søkjemønsteret passa +Comment[pa]=ਖੋਜ ਤਰਤੀਬ ਮੇਲ +Comment[pl]=Dopasowano wzorzec +Comment[pt]=Padrão de pesquisa encontrado +Comment[pt_BR]=Padrão de busca encontrado +Comment[ro]=Modelul căutat s-a potrivit +Comment[ru]=Соответствие шаблону поиска +Comment[rw]=Gushakisha ishusho byahuye +Comment[se]=Ohcanminsttar heivii +Comment[sk]=Nájdené podľa vzorky +Comment[sl]=Iskalni vzorec se ujema +Comment[sr]=Подударан узорак је пронађен +Comment[sr@Latn]=Podudaran uzorak je pronađen +Comment[sv]=Sökmönster igenkänt +Comment[ta]=மாதிரி பொருத்தத்தை தேடு +Comment[th]=ค้นหารูปแบบที่เข้าคู่กัน +Comment[tr]=Eşleşen örüntüyü ara +Comment[tt]=Ezlängäne belän kileşte +Comment[uk]=Знайдено взірець пошуку +Comment[vi]=Tìm các mẫu khớp +Comment[wa]=Trover des modeles ki vont avou +Comment[zh_CN]=搜索匹配的模式 +Comment[zh_TW]=尋找比對正確 + +[sensor_alarm] +Name=sensor_alarm +Name[bn]=বিপদ_সংকেত +Name[cy]=larwm_synhwyrydd +Name[de]=Sensormeldung +Name[eo]=sentilo_alarmo +Name[es]=alarma de sensor +Name[fr]=alarme_des_capteurs +Name[fy]=sensormelding +Name[gl]=alarma_sensor +Name[hi]=सेंसर-अलार्म +Name[hr]=osjetilo_alarma +Name[hu]=érzékelő_riasztás +Name[it]=allarme_dei_sensori +Name[ja]=センサーアラーム +Name[km]=សំឡេងរោទិ៍ឧបករណ៍ស្ទង់ +Name[ko]=센서 알람 +Name[lo]=ການເຕື່ອນກວດຈັບ +Name[lt]=daviklio aliarmas +Name[lv]=sensora_trauksme +Name[mk]=аларм_сензор +Name[mn]=Мэдрэгчийн дохио +Name[nds]=Sensormellen +Name[ne]=सचेतक +Name[nl]=sensormelding +Name[nso]=alamo ya sekwi +Name[pa]=ਸੰਕੇਤਕ ਚੇਤਾਵਨੀ +Name[ro]=alarmă senzor +Name[rw]=impuruza_rukuruzi +Name[se]=dovddan_alarbma +Name[sl]=senzor_alarm +Name[sr]=аларм_сензора +Name[sr@Latn]=alarm_senzora +Name[sv]=sensorlarm +Name[ta]=உணர் எச்சரிக்கை +Name[ven]=Zwipfi_Alamu +Name[vi]=báo động của đầu dò +Name[wa]=sinteu_d'_alarme +Name[xh]=uluvo_oluvusayo +Name[zh_TW]=偵測器通知 +Name[zu]=i-alamu_enemizwa +Comment=Sensor exceeded critical limit +Comment[af]=Sensor oorskry krities beperk +Comment[be]=Сэнсар перавысіў крытычную мяжу +Comment[bg]=Преминат е критичния лимит от даден сензор +Comment[bn]=সেনসর বিপদসীমা ছাড়িয়ে গেছে +Comment[bs]=Senzor je prekoračio kritičnu granicu +Comment[ca]=EL sensor ha excedit el límit crític +Comment[cs]=Senzor překročil kritickou hodnotu +Comment[csb]=Czujnik przestãpił kriticzną grańcã +Comment[cy]=Aethpwyd dros gyfyngder critigol y synhwyrydd +Comment[da]=Sensor gik ud over kritisk grænse +Comment[de]=Sensor zeigt Überschreitung der kritischen Grenze an +Comment[el]=Ο αισθητήρας ξεπέρασε το κρίσιμο όριο +Comment[eo]=Sentilo transiris danĝeran limon +Comment[es]=El sensor excedió el límite crítico +Comment[et]=Sensor ületas kriitilise piiri +Comment[eu]=Sensoreak bere muga kritikoa gainditu du +Comment[fa]=حسگر فراتر از حد بحرانی شد +Comment[fi]=Tunnistin ylitti kriittisen rajan +Comment[fr]=Le capteur a dépassé sa limite critique +Comment[fy]=Sensor limyt giet oer de kritike grins +Comment[gl]=O sensor excedeu o límite crítico +Comment[he]=החיישן חרג מהמגבלה הקריטית +Comment[hi]=सेंसर क्रिटिकल लिमिट से ज्यादा +Comment[hr]=Osjetilo je nadmašilo kritičnu razinu +Comment[hu]=Egy figyelt érték elérte a kritikus szintet +Comment[is]=Skynjari fór yfir hámark +Comment[it]=Il sensore ha superato la soglia critica +Comment[ja]=センサーは危険度の限界を超えました +Comment[ka]=სენსორმა გადააჭარბა კრიტიკულ ზღვარს +Comment[kk]=Сенсор шекті деңгейден асып кетті +Comment[km]=ឧបករណ៍ស្ទង់បានលើសព្រំដែនចុងក្រោយ +Comment[ko]=센서에서 치명적 한계를 넘었음 +Comment[lt]=Daviklis viršijo kritinį limitą +Comment[lv]=Sensors pārsniedzis kritisko limitu +Comment[mk]=Сензорот ја надмина критичната граница +Comment[mn]=Мэдрэгч критик хязгаарын давалтыг заах +Comment[ms]=Penderia melebihi had kritikal +Comment[mt]=Sensur eċċeda l-limitu kritiku +Comment[nb]=Sensorene oversteg en kritisk grense +Comment[nds]=En Sensor hett en Weert meldt, de baven vun de kritische Grenz liggt +Comment[ne]=सचेतक असामान्य सीमा भन्दा अगाडि बढ्यो +Comment[nl]=Sensor overschreed kritieke limiet +Comment[nn]=Sensoren gjekk over kritisk grense +Comment[nso]=Sekwi se fetile magomo a kganetso +Comment[pa]=ਸੰਕੇਤਕ ਘਾਤਕ ਸੀਮਾ ਨੂੰ ਪਾਰ ਕਰ ਗਿਆ ਹੈ +Comment[pl]=Czujnik przekroczył granicę krytyczną +Comment[pt]=o sensor excedeu o limite crítico +Comment[pt_BR]=Sensor excedeu o limite crítico +Comment[ro]=Senzorul a depășit limita critică +Comment[ru]=Датчик превысил критический предел +Comment[rw]= Rukuruzi yarenze impera ngombwa +Comment[sk]=Senzor prekročil kritický limit +Comment[sl]=Senzor je presegel kritično mejo +Comment[sr]=Сензор је прешао дозвољену границу +Comment[sr@Latn]=Senzor je prešao dozvoljenu granicu +Comment[sv]=Sensor överskred den kritiska gränsen +Comment[ta]=உணர்வான் சிக்கல் கட்டத்தை தாண்டியது +Comment[tg]=Датчик аз ҳад гузашт +Comment[th]=ตัวตรวจจับเกินกว่าค่าวิกฤติ +Comment[tr]=Alıcı kritik limiti geçti +Comment[tt]=Sizgeçneñ eşläw waqıtı ütte +Comment[uk]=Датчик перевищив критичний рівень +Comment[uz]=Sensor havfli chegaradan oʻtdi +Comment[uz@cyrillic]=Сенсор ҳавфли чегарадан ўтди +Comment[ven]=Tshisedzi tsho engedza phungudzo i sasaladzeaho +Comment[vi]=Đầu dò vượt quá giới hạn chịu đựng +Comment[wa]=Li sinteu a stî pus lon kel limite +Comment[xh]=Umda wokufumana ingxaki ekhoyo woluvo +Comment[zh_CN]=传感器达到关键限制 +Comment[zh_TW]=偵測器超過臨界限制 +Comment[zu]=Umuzwa udlule isilinganiso esibucayi diff --git a/ksysguard/example/ksysguarddrc b/ksysguard/example/ksysguarddrc new file mode 100644 index 000000000..ba52249fd --- /dev/null +++ b/ksysguard/example/ksysguarddrc @@ -0,0 +1,19 @@ +# /etc/ksysguardd.conf + +# LogFiles: the list of all available logfiles +LogFiles=messages:/var/log/messages,kern:/var/log/kern.log,daemon:/var/log/daemon.log + +# Sensors: the list of all accessable sensors +# ProcessList current processes +# Memory physical memory and swap +# Stat interrupts, CPU and disk throughput +# NetDev throughput of network interfaces +# NetStat number of TCP/UDP/ICMP/Unix sockets +# Apm Advanced Power Managment +# Acpi Advanced Configuration and Power Interface +# CpuInfo CPU-Clock informations +# LoadAvg system load values +# LmSensors informations about motherboard and CPU +# DiskStat partition space +# LogFile local logfiles +Sensors=ProcessList,Memory,Stat,NetDev,NetStat,Apm,Acpi,CpuInfo,LoadAvg,LmSensors,DiskStat,LogFile diff --git a/ksysguard/gui/KSGAppletSettings.cc b/ksysguard/gui/KSGAppletSettings.cc new file mode 100644 index 000000000..df4748cb8 --- /dev/null +++ b/ksysguard/gui/KSGAppletSettings.cc @@ -0,0 +1,106 @@ +/* + This file is part of KSysGuard. + Copyright ( C ) 2002 Nadeem Hasan ( nhasan@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 <qlabel.h> +#include <qlayout.h> +#include <qspinbox.h> + +#include <kaccelmanager.h> +#include <klocale.h> + +#include "KSGAppletSettings.h" + +KSGAppletSettings::KSGAppletSettings( QWidget *parent, const char *name ) + : KDialogBase( parent, name, false, QString::null, Ok|Apply|Cancel, + Ok, true ) +{ + setCaption( i18n( "System Guard Settings" ) ); + + QWidget *page = new QWidget( this ); + setMainWidget( page ); + + QGridLayout *topLayout = new QGridLayout( page, 3, 2, KDialog::marginHint(), + KDialog::spacingHint() ); + + QLabel *label = new QLabel( i18n( "Number of displays:" ), page ); + topLayout->addWidget( label, 0, 0 ); + + mNumDisplay = new QSpinBox( 1, 32, 1, page ); + mNumDisplay->setValue(2); + topLayout->addWidget( mNumDisplay, 0, 1 ); + label->setBuddy( mNumDisplay ); + + label = new QLabel( i18n( "Size ratio:" ), page ); + topLayout->addWidget( label, 1, 0 ); + + mSizeRatio = new QSpinBox( 50, 500, 50, page ); + mSizeRatio->setSuffix( i18n( "%" ) ); + mSizeRatio->setValue(100); + topLayout->addWidget( mSizeRatio, 1, 1 ); + label->setBuddy( mSizeRatio ); + + label = new QLabel( i18n( "Update interval:" ), page ); + topLayout->addWidget( label, 2, 0 ); + + mInterval = new QSpinBox( 1, 300, 1, page ); + mInterval->setValue(2); + mInterval->setSuffix( i18n( " sec" ) ); + topLayout->addWidget( mInterval, 2, 1 ); + label->setBuddy( mInterval ); + + resize( QSize( 250, 130 ).expandedTo( minimumSizeHint() ) ); + + KAcceleratorManager::manage( page ); +} + +KSGAppletSettings::~KSGAppletSettings() +{ +} + +int KSGAppletSettings::numDisplay() const +{ + return mNumDisplay->value(); +} + +void KSGAppletSettings::setNumDisplay( int value ) +{ + mNumDisplay->setValue( value ); +} + +int KSGAppletSettings::sizeRatio() const +{ + return mSizeRatio->value(); +} + +void KSGAppletSettings::setSizeRatio( int value ) +{ + mSizeRatio->setValue( value ); +} + +int KSGAppletSettings::updateInterval() const +{ + return mInterval->value(); +} + +void KSGAppletSettings::setUpdateInterval( int value ) +{ + mInterval->setValue( value ); +} + diff --git a/ksysguard/gui/KSGAppletSettings.h b/ksysguard/gui/KSGAppletSettings.h new file mode 100644 index 000000000..a825e2841 --- /dev/null +++ b/ksysguard/gui/KSGAppletSettings.h @@ -0,0 +1,49 @@ +/* + This file is part of KSysGuard. + Copyright ( C ) 2002 Nadeem Hasan ( nhasan@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 KSG_APPLETSETTINGS_H +#define KSG_APPLETSETTINGS_H + +#include <kdialogbase.h> + +class QSpinBox; + +class KSGAppletSettings : public KDialogBase +{ + public: + KSGAppletSettings( QWidget *parent = 0, const char *name = 0 ); + ~KSGAppletSettings(); + + void setNumDisplay( int ); + int numDisplay() const; + + void setSizeRatio( int ); + int sizeRatio() const; + + void setUpdateInterval( int ); + int updateInterval() const; + + private: + QSpinBox *mInterval; + QSpinBox *mNumDisplay; + QSpinBox *mSizeRatio; +}; + +#endif diff --git a/ksysguard/gui/KSysGuardApplet.cc b/ksysguard/gui/KSysGuardApplet.cc new file mode 100644 index 000000000..5240a068b --- /dev/null +++ b/ksysguard/gui/KSysGuardApplet.cc @@ -0,0 +1,495 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger + <cs@kde.org>. Please do not commit any changes without consulting + me first. Thanks! + +*/ + +#include <qcursor.h> +#include <qdom.h> +#include <qdragobject.h> +#include <qfile.h> +#include <qpushbutton.h> +#include <qspinbox.h> +#include <qtooltip.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <ksavefile.h> +#include <kstandarddirs.h> +#include <kpopupmenu.h> + +#include <ksgrd/SensorClient.h> +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> + +#include "DancingBars.h" +#include "FancyPlotter.h" +#include "KSGAppletSettings.h" +#include "MultiMeter.h" + +#include "KSysGuardApplet.h" + +extern "C" +{ + KDE_EXPORT KPanelApplet* init( QWidget *parent, const QString& configFile ) + { + KGlobal::locale()->insertCatalogue( "ksysguard" ); + return new KSysGuardApplet( configFile, KPanelApplet::Normal, + KPanelApplet::Preferences, parent, + "ksysguardapplet" ); + } +} + +KSysGuardApplet::KSysGuardApplet( const QString& configFile, Type type, + int actions, QWidget *parent, + const char *name ) + : KPanelApplet( configFile, type, actions, parent, name) +{ + mSettingsDlg = 0; + + KSGRD::SensorMgr = new KSGRD::SensorManager(); + + KSGRD::Style = new KSGRD::StyleEngine(); + + mDockCount = 1; + mDockList = new QWidget*[ mDockCount ]; + + mSizeRatio = 1.0; + addEmptyDisplay( mDockList, 0 ); + + updateInterval( 2 ); + + load(); + + setAcceptDrops( true ); +} + +KSysGuardApplet::~KSysGuardApplet() +{ + save(); + + delete [] mDockList; + mDockList = 0; + + delete mSettingsDlg; + mSettingsDlg = 0; + + delete KSGRD::Style; + delete KSGRD::SensorMgr; + KSGRD::SensorMgr = 0; +} + +int KSysGuardApplet::widthForHeight( int height ) const +{ + return ( (int) ( height * mSizeRatio + 0.5 ) * mDockCount ); +} + +int KSysGuardApplet::heightForWidth( int width ) const +{ + return ( (int) ( width * mSizeRatio + 0.5 ) * mDockCount ); +} + +void KSysGuardApplet::resizeEvent( QResizeEvent* ) +{ + layout(); +} + +void KSysGuardApplet::preferences() +{ + if(mSettingsDlg) { + return; + } + mSettingsDlg = new KSGAppletSettings( this ); + + connect( mSettingsDlg, SIGNAL( applyClicked() ), SLOT( applySettings() ) ); + connect( mSettingsDlg, SIGNAL( okClicked() ), SLOT( applySettings() ) ); + connect( mSettingsDlg, SIGNAL( finished() ), SLOT( preferencesFinished() ) ); + + mSettingsDlg->setNumDisplay( mDockCount ); + mSettingsDlg->setSizeRatio( (int) ( mSizeRatio * 100.0 + 0.5 ) ); + mSettingsDlg->setUpdateInterval( updateInterval() ); + + mSettingsDlg->show(); +} +void KSysGuardApplet::preferencesFinished() +{ + mSettingsDlg->delayedDestruct(); + mSettingsDlg = 0; +} +void KSysGuardApplet::applySettings() +{ + updateInterval( mSettingsDlg->updateInterval() ); + mSizeRatio = mSettingsDlg->sizeRatio() / 100.0; + resizeDocks( mSettingsDlg->numDisplay() ); + + for ( uint i = 0; i < mDockCount; ++i ) + if ( !mDockList[ i ]->isA( "QFrame" ) ) + ((KSGRD::SensorDisplay*)mDockList[ i ])->setUpdateInterval( updateInterval() ); + + save(); +} + +void KSysGuardApplet::sensorDisplayModified( bool modified ) +{ + if ( modified ) + save(); +} + +void KSysGuardApplet::layout() +{ + if ( orientation() == Horizontal ) { + int h = height(); + int w = (int) ( h * mSizeRatio + 0.5 ); + for ( uint i = 0; i < mDockCount; ++i ) + if ( mDockList[ i ] ) + mDockList[ i ]->setGeometry( i * w, 0, w, h ); + } else { + int w = width(); + int h = (int) ( w * mSizeRatio + 0.5 ); + for ( uint i = 0; i < mDockCount; ++i ) + if ( mDockList[ i ] ) + mDockList[ i ]->setGeometry( 0, i * h, w, h ); + } +} + +int KSysGuardApplet::findDock( const QPoint& point ) +{ + if ( orientation() == Horizontal ) + return ( point.x() / (int) ( height() * mSizeRatio + 0.5 ) ); + else + return ( point.y() / (int) ( width() * mSizeRatio + 0.5 ) ); +} + +void KSysGuardApplet::dragEnterEvent( QDragEnterEvent *e ) +{ + e->accept( QTextDrag::canDecode( e ) ); +} + +void KSysGuardApplet::dropEvent( QDropEvent *e ) +{ + QString dragObject; + + if ( QTextDrag::decode( e, dragObject ) ) { + // The host name, sensor name and type are seperated by a ' '. + QStringList parts = QStringList::split( ' ', dragObject ); + + QString hostName = parts[ 0 ]; + QString sensorName = parts[ 1 ]; + QString sensorType = parts[ 2 ]; + QString sensorDescr = parts[ 3 ]; + + if ( hostName.isEmpty() || sensorName.isEmpty() || sensorType.isEmpty() ) + return; + + int dock = findDock( e->pos() ); + if ( mDockList[ dock ]->isA( "QFrame" ) ) { + if ( sensorType == "integer" || sensorType == "float" ) { + KPopupMenu popup; + QWidget *wdg = 0; + + popup.insertTitle( i18n( "Select Display Type" ) ); + popup.insertItem( i18n( "&Signal Plotter" ), 1 ); + popup.insertItem( i18n( "&Multimeter" ), 2 ); + popup.insertItem( i18n( "&Dancing Bars" ), 3 ); + switch ( popup.exec( QCursor::pos() ) ) { + case 1: + wdg = new FancyPlotter( this, "FancyPlotter", sensorDescr, + 100.0, 100.0, true ); + break; + + case 2: + wdg = new MultiMeter( this, "MultiMeter", sensorDescr, + 100.0, 100.0, true ); + break; + + case 3: + wdg = new DancingBars( this, "DancingBars", sensorDescr, + 100, 100, true ); + break; + } + + if ( wdg ) { + delete mDockList[ dock ]; + mDockList[ dock ] = wdg; + layout(); + + connect( wdg, SIGNAL( modified( bool ) ), + SLOT( sensorDisplayModified( bool ) ) ); + + mDockList[ dock ]->show(); + } + } else { + KMessageBox::sorry( this, + i18n( "The KSysGuard applet does not support displaying of " + "this type of sensor. Please choose another sensor." ) ); + + layout(); + } + } + + if ( !mDockList[ dock ]->isA( "QFrame" ) ) + ((KSGRD::SensorDisplay*)mDockList[ dock ])-> + addSensor( hostName, sensorName, sensorType, sensorDescr ); + } + + save(); +} + +void KSysGuardApplet::customEvent( QCustomEvent *e ) +{ + if ( e->type() == QEvent::User ) { + // SensorDisplays send out this event if they want to be removed. + removeDisplay( (KSGRD::SensorDisplay*)e->data() ); + save(); + } +} + +void KSysGuardApplet::removeDisplay( KSGRD::SensorDisplay *display ) +{ + for ( uint i = 0; i < mDockCount; ++i ) + if ( display == mDockList[i] ) { + delete mDockList[ i ]; + + addEmptyDisplay( mDockList, i ); + return; + } +} + +void KSysGuardApplet::resizeDocks( uint newDockCount ) +{ + /* This function alters the number of available docks. The number of + * docks can be increased or decreased. We try to preserve existing + * docks if possible. */ + + if ( newDockCount == mDockCount ) { + emit updateLayout(); + return; + } + + // Create and initialize new dock array. + QWidget** tmp = new QWidget*[ newDockCount ]; + + uint i; + for ( i = 0; ( i < newDockCount ) && ( i < mDockCount ); ++i ) + tmp[ i ] = mDockList[ i ]; + + for ( i = newDockCount; i < mDockCount; ++i ) + if ( mDockList[ i ] ) + delete mDockList[ i ]; + + for ( i = mDockCount; i < newDockCount; ++i ) + addEmptyDisplay( tmp, i ); + + delete [] mDockList; + + mDockList = tmp; + mDockCount = newDockCount; + + emit updateLayout(); +} + +bool KSysGuardApplet::load() +{ + KStandardDirs* kstd = KGlobal::dirs(); + kstd->addResourceType( "data", "share/apps/ksysguard" ); + QString fileName = kstd->findResource( "data", "KSysGuardApplet.xml" ); + + QFile file( fileName ); + if ( !file.open( IO_ReadOnly ) ) { + KMessageBox::sorry( this, i18n( "Cannot open the file %1." ).arg( fileName ) ); + return false; + } + + // Parse the XML file. + QDomDocument doc; + + // Read in file and check for a valid XML header. + if ( !doc.setContent( &file ) ) { + KMessageBox::sorry( this, i18n( "The file %1 does not contain valid XML." ) + .arg( fileName ) ); + return false; + } + + // Check for proper document type. + if ( doc.doctype().name() != "KSysGuardApplet" ) { + KMessageBox::sorry( this, i18n( "The file %1 does not contain a valid applet " + "definition, which must have a document type 'KSysGuardApplet'." ) + .arg( fileName ) ); + return false; + } + + QDomElement element = doc.documentElement(); + bool ok; + uint count = element.attribute( "dockCnt" ).toUInt( &ok ); + if ( !ok ) + count = 1; + + mSizeRatio = element.attribute( "sizeRatio" ).toDouble( &ok ); + if ( !ok ) + mSizeRatio = 1.0; + + updateInterval( element.attribute( "interval" ).toUInt( &ok ) ); + if ( !ok ) + updateInterval( 2 ); + + resizeDocks( count ); + + /* Load lists of hosts that are needed for the work sheet and try + * to establish a connection. */ + QDomNodeList dnList = element.elementsByTagName( "host" ); + uint i; + for ( i = 0; i < dnList.count(); ++i ) { + QDomElement element = dnList.item( i ).toElement(); + int port = element.attribute( "port" ).toInt( &ok ); + if ( !ok ) + port = -1; + + KSGRD::SensorMgr->engage( element.attribute( "name" ), + element.attribute( "shell" ), + element.attribute( "command" ), port ); + } + //if no hosts are specified, at least connect to localhost + if(dnList.count() == 0) + KSGRD::SensorMgr->engage( "localhost", "", "ksysguardd", -1); + + // Load the displays and place them into the work sheet. + dnList = element.elementsByTagName( "display" ); + for ( i = 0; i < dnList.count(); ++i ) { + QDomElement element = dnList.item( i ).toElement(); + uint dock = element.attribute( "dock" ).toUInt(); + if ( i >= mDockCount ) { + kdDebug (1215) << "Dock number " << i << " out of range " + << mDockCount << endl; + return false; + } + + QString classType = element.attribute( "class" ); + KSGRD::SensorDisplay* newDisplay; + if ( classType == "FancyPlotter" ) + newDisplay = new FancyPlotter( this, "FancyPlotter", "Dummy", 100.0, 100.0, true /*no frame*/, true /*run ksysguard menu*/); + else if ( classType == "MultiMeter" ) + newDisplay = new MultiMeter( this, "MultiMeter", "Dummy", 100.0, 100.0, true /*no frame*/, true /*run ksysguard menu*/ ); + else if ( classType == "DancingBars" ) + newDisplay = new DancingBars( this, "DancingBars", "Dummy", 100, 100, true /*no frame*/, true /*run ksysguard menu*/); + else { + KMessageBox::sorry( this, i18n( "The KSysGuard applet does not support displaying of " + "this type of sensor. Please choose another sensor." ) ); + return false; + } + + newDisplay->setUpdateInterval( updateInterval() ); + + // load display specific settings + if ( !newDisplay->restoreSettings( element ) ) + return false; + + delete mDockList[ dock ]; + mDockList[ dock ] = newDisplay; + + connect( newDisplay, SIGNAL( modified( bool ) ), + SLOT( sensorDisplayModified( bool ) ) ); + } + + return true; +} + +bool KSysGuardApplet::save() +{ + // Parse the XML file. + QDomDocument doc( "KSysGuardApplet" ); + doc.appendChild( doc.createProcessingInstruction( + "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); + + // save work sheet information + QDomElement ws = doc.createElement( "WorkSheet" ); + doc.appendChild( ws ); + ws.setAttribute( "dockCnt", mDockCount ); + ws.setAttribute( "sizeRatio", mSizeRatio ); + ws.setAttribute( "interval", updateInterval() ); + + QStringList hosts; + uint i; + for ( i = 0; i < mDockCount; ++i ) + if ( !mDockList[ i ]->isA( "QFrame" ) ) + ((KSGRD::SensorDisplay*)mDockList[ i ])->hosts( hosts ); + + // save host information (name, shell, etc.) + QStringList::Iterator it; + for ( it = hosts.begin(); it != hosts.end(); ++it ) { + QString shell, command; + int port; + + if ( KSGRD::SensorMgr->hostInfo( *it, shell, command, port ) ) { + QDomElement host = doc.createElement( "host" ); + ws.appendChild( host ); + host.setAttribute( "name", *it ); + host.setAttribute( "shell", shell ); + host.setAttribute( "command", command ); + host.setAttribute( "port", port ); + } + } + + for ( i = 0; i < mDockCount; ++i ) + if ( !mDockList[ i ]->isA( "QFrame" ) ) { + QDomElement element = doc.createElement( "display" ); + ws.appendChild( element ); + element.setAttribute( "dock", i ); + element.setAttribute( "class", mDockList[ i ]->className() ); + + ((KSGRD::SensorDisplay*)mDockList[ i ])->saveSettings( doc, element ); + } + + KStandardDirs* kstd = KGlobal::dirs(); + kstd->addResourceType( "data", "share/apps/ksysguard" ); + QString fileName = kstd->saveLocation( "data", "ksysguard" ); + fileName += "/KSysGuardApplet.xml"; + + KSaveFile file( fileName, 0644 ); + + if ( file.status() == 0 ) + { + file.textStream()->setEncoding( QTextStream::UnicodeUTF8 ); + *(file.textStream()) << doc; + file.close(); + } + else + { + KMessageBox::sorry( this, i18n( "Cannot save file %1" ).arg( fileName ) ); + return false; + } + + return true; +} + +void KSysGuardApplet::addEmptyDisplay( QWidget **dock, uint pos ) +{ + dock[ pos ] = new QFrame( this ); + ((QFrame*)dock[ pos ])->setFrameStyle( QFrame::WinPanel | QFrame::Sunken ); + QToolTip::add( dock[ pos ], + i18n( "Drag sensors from the KDE System Guard into this cell." ) ); + + layout(); + if ( isVisible() ) + dock[ pos ]->show(); +} + +#include "KSysGuardApplet.moc" diff --git a/ksysguard/gui/KSysGuardApplet.h b/ksysguard/gui/KSysGuardApplet.h new file mode 100644 index 000000000..b9d91091e --- /dev/null +++ b/ksysguard/gui/KSysGuardApplet.h @@ -0,0 +1,85 @@ +/* + KKSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger + <cs@kde.org>. Please do not commit any changes without consulting + me first. Thanks! + +*/ + +#ifndef KSG_KSYSGUARDAPPLET_H +#define KSG_KSYSGUARDAPPLET_H + +#include <kpanelapplet.h> + +namespace KSGRD +{ +class SensorBoard; +class SensorDisplay; +} + +class QDragEnterEvent; +class QDropEvent; +class QPoint; +class KSGAppletSettings; + +class KSysGuardApplet : public KPanelApplet, public KSGRD::SensorBoard +{ + Q_OBJECT + + public: + KSysGuardApplet( const QString& configFile, Type type = Normal, + int actions = 0, QWidget *parent = 0, + const char *name = 0 ); + virtual ~KSysGuardApplet(); + + virtual int heightForWidth( int width ) const; + virtual int widthForHeight( int height ) const; + + virtual void preferences(); + + protected: + void resizeEvent( QResizeEvent* ); + void dragEnterEvent( QDragEnterEvent* ); + void dropEvent( QDropEvent* ); + void customEvent( QCustomEvent* ); + + + private slots: + void applySettings(); + void sensorDisplayModified( bool ); + void preferencesFinished(); + + private: + void layout(); + void resizeDocks( uint newDockCount ); + void addEmptyDisplay( QWidget **dock, uint pos ); + + bool load(); + bool save(); + + int findDock( const QPoint& ); + void removeDisplay( KSGRD::SensorDisplay* ); + + double mSizeRatio; + uint mDockCount; + KSGAppletSettings* mSettingsDlg; + QWidget** mDockList; +}; + +#endif diff --git a/ksysguard/gui/KSysGuardApplet.xml b/ksysguard/gui/KSysGuardApplet.xml new file mode 100644 index 000000000..2f115f61e --- /dev/null +++ b/ksysguard/gui/KSysGuardApplet.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE KSysGuardApplet> +<WorkSheet sizeRatio="1.2" dockCnt="2" interval="4" > + <host port="-1" shell="" name="localhost" command="ksysguardd" /> + <display topBar="1" vColor="326429" title="CPU" dock="0" bColor="3223601" graphStyle="0" class="FancyPlotter" unit="" hScale="1" showUnit="0" hLines="1" hCount="2" vLines="1" autoRange="1" min="0" max="0" hColor="14606046" globalUpdate="1" pause="0" fontSize="8" labels="1" vScroll="1" vDistance="30" > + <beam sensorName="cpu/user" hostName="localhost" color="1608191" sensorType="integer" /> + <beam sensorName="cpu/sys" hostName="localhost" color="16743688" sensorType="integer" /> + <beam sensorName="cpu/nice" hostName="localhost" color="16771600" sensorType="integer" /> + </display> + <display topBar="1" vColor="4605510" title="Mem" dock="1" bColor="3223601" graphStyle="0" class="FancyPlotter" unit="" hScale="5" showUnit="0" hLines="1" hCount="2" vLines="0" autoRange="1" min="0" max="0" hColor="14606046" globalUpdate="1" pause="0" fontSize="8" labels="0" vScroll="1" vDistance="30" > + <beam sensorName="mem/physical/application" hostName="localhost" color="1608191" sensorType="integer" /> + <beam sensorName="mem/physical/buf" hostName="localhost" color="16743688" sensorType="integer" /> + <beam sensorName="mem/physical/cached" hostName="localhost" color="16771600" sensorType="integer" /> + </display> +</WorkSheet> diff --git a/ksysguard/gui/Makefile.am b/ksysguard/gui/Makefile.am new file mode 100644 index 000000000..c0b9d12b3 --- /dev/null +++ b/ksysguard/gui/Makefile.am @@ -0,0 +1,63 @@ + +kdemimedir = $(kde_mimedir)/application +kdemime_DATA = x-ksysguard.desktop + +rcdir = $(kde_datadir)/ksysguard +rc_DATA = ksysguardui.rc + +xdg_apps_DATA = ksysguard.desktop + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = ksysguardapplet.desktop + +# claim, which subdirectories you want to install +SUBDIRS = ksgrd SensorDisplayLib + +# set the include path for X, qt and KDE +INCLUDES = -I$(srcdir)/ksgrd -I$(srcdir)/SensorDisplayLib -I$(top_builddir)/ksysguard/gui/SensorDisplayLib $(all_includes) + +####### This part is very ksysguard specific +# you can add here more. This one gets installed +bin_PROGRAMS = ksysguard kpm + +# Which sources should be compiled for ksysguard. +ksysguard_SOURCES = \ + SensorBrowser.cc \ + WorkSheet.cc \ + WorkSheetSettings.cc \ + Workspace.cc \ + ksysguard.cc ksysguard.skel + +ksysguard_LDADD = \ + ksgrd/libksgrd.la \ + SensorDisplayLib/libsensordisplays.la \ + $(LIB_KDEUI) $(LIB_KIO) $(LIB_KDNSSD) +ksysguard_LDFLAGS = $(all_libraries) $(KDE_RPATH) + +kpm_SOURCES = kpm.c + +appdatadir = $(kde_datadir)/ksysguard +appdata_DATA = ProcessTable.sgrd SystemLoad.sgrd KSysGuardApplet.xml + +# This stuff is now for the kicker applet +kde_module_LTLIBRARIES = sysguard_panelapplet.la + +sysguard_panelapplet_la_SOURCES = \ + KSysGuardApplet.cc \ + KSGAppletSettings.cc + +sysguard_panelapplet_la_LIBADD = \ + ksgrd/libksgrd.la \ + SensorDisplayLib/libsensordisplays.la \ + $(LIB_KDEUI) $(LIB_KIO) +sysguard_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) + +EXTRA_DIST = $(lnk_DATA) + +# just to make sure, automake makes them +METASOURCES = AUTO + +messages: rc.cpp + $(EXTRACTRC) `find . -name "*.ui"` >> rc.cpp + $(EXTRACTATTR) --attr=display,title SystemLoad.sgrd KSysGuardApplet.xml >> rc.cpp + $(XGETTEXT) `find . -name "*.cpp" -o -name "*.cc"` -o $(podir)/ksysguard.pot diff --git a/ksysguard/gui/ProcessTable.sgrd b/ksysguard/gui/ProcessTable.sgrd new file mode 100644 index 000000000..2717a2b9d --- /dev/null +++ b/ksysguard/gui/ProcessTable.sgrd @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE KSysGuardWorkSheet> +<WorkSheet rows="1" interval="2" columns="1" > + <host port="-1" shell="" name="localhost" command="ksysguardd" /> + <display title="" class="ProcessController" row="0" unit="" sensorName="ps" column="0" filter="0" showUnit="0" sortColumn="0" hostName="localhost" globalUpdate="1" incrOrder="1" tree="0" sensorType="table" pause="0" > + <column currentWidth="127" savedWidth="126" index="0" /> + <column currentWidth="42" savedWidth="46" index="1" /> + <column currentWidth="0" savedWidth="42" index="2" /> + <column currentWidth="0" savedWidth="33" index="3" /> + <column currentWidth="0" savedWidth="42" index="4" /> + <column currentWidth="0" savedWidth="66" index="5" /> + <column currentWidth="52" savedWidth="45" index="6" /> + <column currentWidth="72" savedWidth="48" index="7" /> + <column currentWidth="38" savedWidth="36" index="8" /> + <column currentWidth="57" savedWidth="65" index="9" /> + <column currentWidth="52" savedWidth="30" index="10" /> + <column currentWidth="56" savedWidth="150" index="11" /> + <column currentWidth="402" savedWidth="150" index="12" /> + </display> +</WorkSheet> diff --git a/ksysguard/gui/SensorBrowser.cc b/ksysguard/gui/SensorBrowser.cc new file mode 100644 index 000000000..969978947 --- /dev/null +++ b/ksysguard/gui/SensorBrowser.cc @@ -0,0 +1,412 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#include <qdragobject.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +#include <kdebug.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <ksgrd/SensorManager.h> + +#include "SensorBrowser.h" + +class HostItem : public QListViewItem +{ + public: + HostItem( SensorBrowser *parent, const QString &text, int id, + KSGRD::SensorAgent *host) + : QListViewItem( parent, text ), mInited( false ), mId( id ), + mHost( host ), mParent( parent ) + { + setExpandable( true ); + } + + void setOpen( bool open ) + { + if ( open && !mInited ) { + mInited = true; + // request sensor list from host + mHost->sendRequest( "monitors", mParent, mId ); + } + + QListViewItem::setOpen( open ); + } + + private: + bool mInited; + int mId; + KSGRD::SensorAgent* mHost; + SensorBrowser* mParent; +}; + +SensorBrowser::SensorBrowser( QWidget* parent, KSGRD::SensorManager* sm, + const char* name) + : KListView( parent, name ), mSensorManager( sm ) +{ + mHostInfoList.setAutoDelete(true); + + connect( mSensorManager, SIGNAL( update() ), SLOT( update() ) ); + connect( this, SIGNAL( clicked( QListViewItem* ) ), + SLOT( newItemSelected( QListViewItem* ) ) ); + connect( this, SIGNAL( returnPressed( QListViewItem* ) ), + SLOT( newItemSelected( QListViewItem* ) ) ); + + addColumn( i18n( "Sensor Browser" ) ); + addColumn( i18n( "Sensor Type" ) ); + setFullWidth( true ); + + QToolTip::add( this, i18n( "Drag sensors to empty cells of a worksheet " + "or the panel applet." ) ); + setRootIsDecorated( true ); + + // The sensor browser can be completely hidden. + setMinimumWidth( 1 ); + + QWhatsThis::add( this, i18n( "The sensor browser lists the connected hosts and the sensors " + "that they provide. Click and drag sensors into drop zones " + "of a worksheet or the panel applet. A display will appear " + "that visualizes the " + "values provided by the sensor. Some sensor displays can " + "display values of multiple sensors. Simply drag other " + "sensors on to the display to add more sensors." ) ); +} + +SensorBrowser::~SensorBrowser() +{ +} + +void SensorBrowser::disconnect() +{ + QPtrListIterator<HostInfo> it( mHostInfoList ); + + for ( ; it.current(); ++it ) + if ( (*it)->listViewItem()->isSelected() ) { + kdDebug(1215) << "Disconnecting " << (*it)->hostName() << endl; + KSGRD::SensorMgr->requestDisengage( (*it)->sensorAgent() ); + } +} + +void SensorBrowser::hostReconfigured( const QString& ) +{ + // TODO: not yet implemented. +} + +void SensorBrowser::update() +{ + static int id = 0; + + KSGRD::SensorManagerIterator it( mSensorManager ); + + mHostInfoList.clear(); + clear(); + + KSGRD::SensorAgent* host; + for ( int i = 0 ; ( host = it.current() ); ++it, ++i ) { + QString hostName = mSensorManager->hostName( host ); + HostItem* lvi = new HostItem( this, hostName, id, host ); + + QPixmap pix = KGlobal::iconLoader()->loadIcon( "computer", KIcon::Desktop, KIcon::SizeSmall ); + lvi->setPixmap( 0, pix ); + + HostInfo* hostInfo = new HostInfo( id, host, hostName, lvi ); + mHostInfoList.append( hostInfo ); + ++id; + } + + setMouseTracking( false ); +} + +void SensorBrowser::newItemSelected( QListViewItem *item ) +{ + static bool showAnnoyingPopup = true; + if ( item && item->pixmap( 0 ) && showAnnoyingPopup) + { + showAnnoyingPopup = false; + KMessageBox::information( this, i18n( "Drag sensors to empty fields in a worksheet." ), + QString::null, "ShowSBUseInfo" ); + } +} + +void SensorBrowser::answerReceived( int id, const QString &answer ) +{ + /* An answer has the following format: + + cpu/idle integer + cpu/sys integer + cpu/nice integer + cpu/user integer + ps table + */ + + QPtrListIterator<HostInfo> it( mHostInfoList ); + + /* Check if id is still valid. It can get obsolete by rapid calls + * of update() or when the sensor died. */ + for ( ; it.current(); ++it ) + if ( (*it)->id() == id ) + break; + + if ( !it.current() ) + return; + + KSGRD::SensorTokenizer lines( answer, '\n' ); + + for ( uint i = 0; i < lines.count(); ++i ) { + if ( lines[ i ].isEmpty() ) + break; + + KSGRD::SensorTokenizer words( lines[ i ], '\t' ); + QString sensorName = words[ 0 ]; + QString sensorType = words[ 1 ]; + + /* Calling update() a rapid sequence will create pending + * requests that do not get erased by calling + * clear(). Subsequent updates will receive the old pending + * answers so we need to make sure that we register each + * sensor only once. */ + if ( (*it)->isRegistered( sensorName ) ) + return; + + /* The sensor browser can display sensors in a hierachical order. + * Sensors can be grouped into nodes by seperating the hierachical + * nodes through slashes in the sensor name. E. g. cpu/user is + * the sensor user in the cpu node. There is no limit for the + * depth of nodes. */ + KSGRD::SensorTokenizer absolutePath( sensorName, '/' ); + + QListViewItem* parent = (*it)->listViewItem(); + for ( uint j = 0; j < absolutePath.count(); ++j ) { + // Localize the sensor name part by part. + QString name = KSGRD::SensorMgr->translateSensorPath( absolutePath[ j ] ); + + bool found = false; + QListViewItem* sibling = parent->firstChild(); + while ( sibling && !found ) { + if (sibling->text( 0 ) == name ) { + // The node or sensor is already known. + found = true; + } else + sibling = sibling->nextSibling(); + } + if ( !found ) { + QListViewItem* lvi = new QListViewItem( parent, name ); + if ( j == absolutePath.count() - 1 ) { + QPixmap pix = KGlobal::iconLoader()->loadIcon( "ksysguardd", KIcon::Desktop, + KIcon::SizeSmall ); + lvi->setPixmap( 0, pix ); + lvi->setText( 1, KSGRD::SensorMgr->translateSensorType( sensorType ) ); + + // add sensor info to internal data structure + (*it)->addSensor( lvi, sensorName, name, sensorType ); + } else + parent = lvi; + + // The child indicator might need to be updated. + repaintItem( parent ); + } else + parent = sibling; + } + } + + repaintItem( (*it)->listViewItem() ); +} + +void SensorBrowser::viewportMouseMoveEvent( QMouseEvent *e ) +{ + /* setMouseTracking(false) seems to be broken. With current Qt + * mouse tracking cannot be turned off. So we have to check each event + * whether the LMB is really pressed. */ + + if ( !( e->state() & LeftButton ) ) + return; + + QListViewItem* item = itemAt( e->pos() ); + if ( !item ) // no item under cursor + return; + + // Make sure that a sensor and not a node or hostname has been picked. + QPtrListIterator<HostInfo> it( mHostInfoList ); + for ( ; it.current() && !(*it)->isRegistered( item ); ++it ); + if ( !it.current() ) + return; + + // Create text drag object as + // "<hostname> <sensorname> <sensortype> <sensordescription>". + // Only the description may contain blanks. + mDragText = (*it)->hostName() + " " + + (*it)->sensorName( item ) + " " + + (*it)->sensorType( item ) + " " + + (*it)->sensorDescription( item ); + + QDragObject* dragObject = new QTextDrag( mDragText, this ); + dragObject->dragCopy(); +} + +QStringList SensorBrowser::listHosts() +{ + QStringList hostList; + + QPtrListIterator<HostInfo> it( mHostInfoList ); + for ( ; it.current(); ++it ) + hostList.append( (*it)->hostName() ); + + return hostList; +} + +QStringList SensorBrowser::listSensors( const QString &hostName ) +{ + QPtrListIterator<HostInfo> it( mHostInfoList ); + for ( ; it.current(); ++it ) { + if ( (*it)->hostName() == hostName ) { + return (*it)->allSensorNames(); + } + } + + return QStringList(); +} + +/** + Helper classes + */ +SensorInfo::SensorInfo( QListViewItem *lvi, const QString &name, + const QString &desc, const QString &type ) + : mLvi( lvi ), mName( name ), mDesc( desc ), mType( type ) +{ +} + +QListViewItem* SensorInfo::listViewItem() const +{ + return mLvi; +} + +const QString& SensorInfo::name() const +{ + return mName; +} + +const QString& SensorInfo::type() const +{ + return mType; +} + +const QString& SensorInfo::description() const +{ + return mDesc; +} + +HostInfo::HostInfo( int id, const KSGRD::SensorAgent *agent, + const QString &name, QListViewItem *lvi ) + : mId( id ), mSensorAgent( agent ), mHostName( name ), mLvi( lvi ) +{ + mSensorList.setAutoDelete( true ); +} + +int HostInfo::id() const +{ + return ( mId ); +} + +const KSGRD::SensorAgent* HostInfo::sensorAgent() const +{ + return mSensorAgent; +} + +const QString& HostInfo::hostName() const +{ + return mHostName; +} + +QListViewItem* HostInfo::listViewItem() const +{ + return mLvi; +} + +const QString& HostInfo::sensorName( const QListViewItem *lvi ) const +{ + QPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current() && (*it)->listViewItem() != lvi; ++it ); + + Q_ASSERT( it.current() ); + return ( (*it)->name() ); +} + +QStringList HostInfo::allSensorNames() const +{ + QStringList list; + + QPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current(); ++it ) + list.append( it.current()->name() ); + + return list; +} + +const QString& HostInfo::sensorType( const QListViewItem *lvi ) const +{ + QPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current() && (*it)->listViewItem() != lvi; ++it ); + + Q_ASSERT( it.current() ); + return ( (*it)->type() ); +} + +const QString& HostInfo::sensorDescription( const QListViewItem *lvi ) const +{ + QPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current() && (*it)->listViewItem() != lvi; ++it ); + + Q_ASSERT( it.current() ); + return ( (*it)->description() ); +} + +void HostInfo::addSensor( QListViewItem *lvi, const QString& name, + const QString& desc, const QString& type ) +{ + SensorInfo* info = new SensorInfo( lvi, name, desc, type ); + mSensorList.append( info ); +} + +bool HostInfo::isRegistered( const QString& name ) const +{ + QPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current(); ++it ) + if ( (*it)->name() == name ) + return true; + + return false; +} + +bool HostInfo::isRegistered( QListViewItem *lvi ) const +{ + QPtrListIterator<SensorInfo> it( mSensorList ); + for ( ; it.current(); ++it ) + if ( (*it)->listViewItem() == lvi ) + return true; + + return false; +} + +#include "SensorBrowser.moc" diff --git a/ksysguard/gui/SensorBrowser.h b/ksysguard/gui/SensorBrowser.h new file mode 100644 index 000000000..9021166d9 --- /dev/null +++ b/ksysguard/gui/SensorBrowser.h @@ -0,0 +1,193 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_SENSORBROWSER_H +#define KSG_SENSORBROWSER_H + +#include <qdict.h> + +#include <klistview.h> +#include <ksgrd/SensorClient.h> + +class QMouseEvent; + +namespace KSGRD { +class SensorManager; +class SensorAgent; +} + +class SensorInfo; +class HostInfo; + +/** + * The SensorBrowser is the graphical front-end of the SensorManager. It + * displays the currently available hosts and their sensors. + */ +class SensorBrowser : public KListView, public KSGRD::SensorClient +{ + Q_OBJECT + + public: + SensorBrowser( QWidget* parent, KSGRD::SensorManager* sm, const char* name = 0 ); + ~SensorBrowser(); + + QStringList listHosts(); + QStringList listSensors( const QString &hostName ); + + public slots: + void disconnect(); + void hostReconfigured( const QString &hostName ); + void update(); + void newItemSelected( QListViewItem *item ); + + protected: + virtual void viewportMouseMoveEvent( QMouseEvent* ); + + private: + void answerReceived( int id, const QString& ); + + KSGRD::SensorManager* mSensorManager; + + QPtrList<HostInfo> mHostInfoList; + QString mDragText; + +}; + +/** + Helper classes + */ +class SensorInfo +{ + public: + SensorInfo( QListViewItem *lvi, const QString &name, const QString &desc, + const QString &type ); + ~SensorInfo() {} + + /** + Returns a pointer to the list view item of the sensor. + */ + QListViewItem* listViewItem() const; + + /** + Returns the name of the sensor. + */ + const QString& name() const; + + /** + Returns the description of the sensor. + */ + const QString& description() const; + + /** + Returns the type of the sensor. + */ + const QString& type() const; + + private: + QListViewItem* mLvi; + QString mName; + QString mDesc; + QString mType; +}; + +class HostInfo +{ + public: + HostInfo( int id, const KSGRD::SensorAgent *agent, const QString &name, + QListViewItem *lvi ); + ~HostInfo() { } + + /** + Returns the unique id of the host. + */ + int id() const; + + /** + Returns a pointer to the sensor agent of the host. + */ + const KSGRD::SensorAgent* sensorAgent() const; + + /** + Returns the name of the host. + */ + const QString& hostName() const; + + /** + Returns the a pointer to the list view item of the host. + */ + QListViewItem* listViewItem() const; + + /** + Returns the sensor name of a special list view item. + */ + const QString& sensorName( const QListViewItem *lvi ) const; + + /** + Returns all sensor names of the host. + */ + QStringList allSensorNames() const; + + /** + Returns the type of a special list view item. + */ + const QString& sensorType( const QListViewItem *lvi ) const; + + /** + Returns the description of a special list view item. + */ + const QString& sensorDescription( const QListViewItem *lvi ) const; + + /** + Adds a new Sensor to the host. + + @param lvi The list view item. + @param name The sensor name. + @param desc A description. + @param type The type of the sensor. + */ + void addSensor( QListViewItem *lvi, const QString& name, + const QString& desc, const QString& type ); + + /** + Returns whether the sensor with @ref name + is registered at the host. + */ + bool isRegistered( const QString& name ) const; + + /** + Returns whether the sensor with @ref lvi + is registered at the host. + */ + bool isRegistered( QListViewItem *lvi ) const; + + private: + int mId; + + const KSGRD::SensorAgent* mSensorAgent; + const QString mHostName; + QListViewItem* mLvi; + + QPtrList<SensorInfo> mSensorList; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/BarGraph.cc b/ksysguard/gui/SensorDisplayLib/BarGraph.cc new file mode 100644 index 000000000..f6dc741cb --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/BarGraph.cc @@ -0,0 +1,177 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <assert.h> +#include <string.h> + +#include <qpainter.h> + +#include <kdebug.h> +#include <kiconloader.h> + +#include <ksgrd/StyleEngine.h> + +#include "BarGraph.h" + +BarGraph::BarGraph( QWidget *parent, const char *name ) + : QWidget( parent, name ) +{ + // paintEvent covers whole widget so we use no background to avoid flicker + setBackgroundMode( NoBackground ); + + bars = 0; + minValue = 0.0; + maxValue = 100.0; + lowerLimit = upperLimit = 0.0; + lowerLimitActive = upperLimitActive = false; + + normalColor = KSGRD::Style->firstForegroundColor(); + alarmColor = KSGRD::Style->alarmColor(); + backgroundColor = KSGRD::Style->backgroundColor(); + fontSize = KSGRD::Style->fontSize(); + + // Anything smaller than this does not make sense. + setMinimumSize( 16, 16 ); + setSizePolicy( QSizePolicy( QSizePolicy::Expanding, + QSizePolicy::Expanding, false ) ); +} + +BarGraph::~BarGraph() +{ +} + +bool BarGraph::addBar( const QString &footer ) +{ + samples.resize( bars + 1 ); + samples[ bars++ ] = 0.0; + footers.append( footer ); + + return true; +} + +bool BarGraph::removeBar( uint idx ) +{ + if ( idx >= bars ) { + kdDebug(1215) << "BarGraph::removeBar: idx " << idx << " out of range " + << bars << endl; + return false; + } + + samples.resize( --bars ); + footers.remove( footers.at( idx ) ); + update(); + + return true; +} + +void BarGraph::updateSamples( const QMemArray<double> &newSamples ) +{ + samples = newSamples; + update(); +} + +void BarGraph::changeRange( double min, double max ) +{ + minValue = min; + maxValue = max; +} + +void BarGraph::paintEvent( QPaintEvent* ) +{ + int w = width(); + int h = height(); + + QPixmap pm( w, h ); + QPainter p; + p.begin( &pm, this ); + p.setFont( QFont( p.font().family(), fontSize ) ); + QFontMetrics fm( p.font() ); + + pm.fill( backgroundColor ); + + /* Draw white line along the bottom and the right side of the + * widget to create a 3D like look. */ + p.setPen( QColor( colorGroup().light() ) ); + p.drawLine( 0, h - 1, w - 1, h - 1 ); + p.drawLine( w - 1, 0, w - 1, h - 1 ); + + p.setClipRect( 1, 1, w - 2, h - 2 ); + + if ( bars > 0 ) { + int barWidth = ( w - 2 ) / bars; + uint b; + /* Labels are only printed underneath the bars if the labels + * for all bars are smaller than the bar width. If a single + * label does not fit no label is shown. */ + bool showLabels = true; + for ( b = 0; b < bars; b++ ) + if ( fm.width( footers[ b ] ) > barWidth ) + showLabels = false; + + int barHeight; + if ( showLabels ) + barHeight = h - 2 - ( 2 * fm.lineSpacing() ) - 2; + else + barHeight = h - 2; + + for ( uint b = 0; b < bars; b++ ) { + int topVal = (int) ( (float)barHeight / maxValue * + ( samples[ b ] - minValue ) ); + /* TODO: This widget does not handle negative values properly. */ + if ( topVal < 0 ) + topVal = 0; + + for ( int i = 0; i < barHeight && i < topVal; i += 2 ) { + if ( ( upperLimitActive && samples[ b ] > upperLimit ) || + ( lowerLimitActive && samples[ b ] < lowerLimit ) ) + p.setPen( alarmColor.light( static_cast<int>( 30 + ( 70.0 / + ( barHeight + 1 ) * i ) ) ) ); + else + p.setPen( normalColor.light( static_cast<int>( 30 + ( 70.0 / + ( barHeight + 1 ) * i ) ) ) ); + p.drawLine( b * barWidth + 3, barHeight - i, ( b + 1 ) * barWidth - 3, + barHeight - i ); + } + + if ( ( upperLimitActive && samples[ b ] > upperLimit ) || + ( lowerLimitActive && samples[ b ] < lowerLimit ) ) + p.setPen( alarmColor ); + else + p.setPen( normalColor ); + + if ( showLabels ) { + p.drawText( b * barWidth + 3, h - ( 2 * fm.lineSpacing() ) - 2, + barWidth - 2 * 3, fm.lineSpacing(), Qt::AlignCenter, + footers[ b ] ); + p.drawText( b * barWidth + 3, h - fm.lineSpacing() - 2, + barWidth - 2 * 3, fm.lineSpacing(), Qt::AlignCenter, + QString( "%1" ).arg( samples[ b ] ) ); + } + } + } + + p.end(); + bitBlt( this, 0, 0, &pm ); +} + +#include "BarGraph.moc" diff --git a/ksysguard/gui/SensorDisplayLib/BarGraph.h b/ksysguard/gui/SensorDisplayLib/BarGraph.h new file mode 100644 index 000000000..aca20c629 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/BarGraph.h @@ -0,0 +1,94 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_BARGRAPH_H +#define KSG_BARGRAPH_H + +#include <qmemarray.h> +#include <qptrvector.h> +#include <qwidget.h> + +class BarGraph : public QWidget +{ + Q_OBJECT + + friend class DancingBars; + + public: + BarGraph( QWidget *parent, const char *name = 0 ); + ~BarGraph(); + + bool addBar( const QString &footer ); + bool removeBar( uint idx ); + + void updateSamples( const QMemArray<double> &newSamples ); + + double getMin() const + { + return minValue; + } + + double getMax() const + { + return maxValue; + } + + void getLimits( double &l, bool &la, double &u, bool &ua ) const + { + l = lowerLimit; + la = lowerLimitActive; + u = upperLimit; + ua = upperLimitActive; + } + + void setLimits( double l, bool la, double u, bool ua ) + { + lowerLimit = l; + lowerLimitActive = la; + upperLimit = u; + upperLimitActive = ua; + } + + void changeRange( double min, double max ); + + protected: + virtual void paintEvent( QPaintEvent* ); + + private: + double minValue; + double maxValue; + double lowerLimit; + double lowerLimitActive; + double upperLimit; + bool upperLimitActive; + bool autoRange; + QMemArray<double> samples; + QStringList footers; + uint bars; + QColor normalColor; + QColor alarmColor; + QColor backgroundColor; + int fontSize; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/DancingBars.cc b/ksysguard/gui/SensorDisplayLib/DancingBars.cc new file mode 100644 index 000000000..48c360713 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DancingBars.cc @@ -0,0 +1,353 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000, 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <qcheckbox.h> +#include <qdom.h> +#include <qlineedit.h> +#include <qlistview.h> +#include <qpushbutton.h> +#include <qspinbox.h> +#include <qtooltip.h> + +#include <kdebug.h> +#include <klocale.h> +#include <knumvalidator.h> +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> + +#include "BarGraph.h" +#include "DancingBarsSettings.h" + +#include "DancingBars.h" + +DancingBars::DancingBars( QWidget *parent, const char *name, const QString &title, + int, int, bool noFrame_, bool isApplet ) + : KSGRD::SensorDisplay( parent, name, title, noFrame_, isApplet ) +{ + mBars = 0; + mFlags = QBitArray(100); + mFlags.fill( false ); + + if ( noFrame() ) + mPlotter = new BarGraph( this ); + else + mPlotter = new BarGraph( frame() ); + + setMinimumSize( sizeHint() ); + + /* All RMB clicks to the mPlotter widget will be handled by + * SensorDisplay::eventFilter. */ + mPlotter->installEventFilter( this ); + + setPlotterWidget( mPlotter ); + + setModified( false ); +} + +DancingBars::~DancingBars() +{ +} + +void DancingBars::configureSettings() +{ + mSettingsDialog = new DancingBarsSettings( this ); + + mSettingsDialog->setTitle( title() ); + mSettingsDialog->setMinValue( mPlotter->getMin() ); + mSettingsDialog->setMaxValue( mPlotter->getMax() ); + + double l, u; + bool la, ua; + mPlotter->getLimits( l, la, u, ua ); + + mSettingsDialog->setUseUpperLimit( ua ); + mSettingsDialog->setUpperLimit( u ); + + mSettingsDialog->setUseLowerLimit( la ); + mSettingsDialog->setLowerLimit( l ); + + mSettingsDialog->setForegroundColor( mPlotter->normalColor ); + mSettingsDialog->setAlarmColor( mPlotter->alarmColor ); + mSettingsDialog->setBackgroundColor( mPlotter->backgroundColor ); + mSettingsDialog->setFontSize( mPlotter->fontSize ); + + QValueList< QStringList > list; + for ( uint i = mBars - 1; i < mBars; i-- ) { + QStringList entry; + entry << sensors().at( i )->hostName(); + entry << KSGRD::SensorMgr->translateSensor( sensors().at( i )->name() ); + entry << mPlotter->footers[ i ]; + entry << KSGRD::SensorMgr->translateUnit( sensors().at( i )->unit() ); + entry << ( sensors().at( i )->isOk() ? i18n( "OK" ) : i18n( "Error" ) ); + + list.append( entry ); + } + mSettingsDialog->setSensors( list ); + + connect( mSettingsDialog, SIGNAL( applyClicked() ), SLOT( applySettings() ) ); + + if ( mSettingsDialog->exec() ) + applySettings(); + + delete mSettingsDialog; + mSettingsDialog = 0; +} + +void DancingBars::applySettings() +{ + setTitle( mSettingsDialog->title() ); + mPlotter->changeRange( mSettingsDialog->minValue(), mSettingsDialog->maxValue() ); + mPlotter->setLimits( mSettingsDialog->useLowerLimit() ? + mSettingsDialog->lowerLimit() : 0, + mSettingsDialog->useLowerLimit(), + mSettingsDialog->useUpperLimit() ? + mSettingsDialog->upperLimit() : 0, + mSettingsDialog->useUpperLimit() ); + + mPlotter->normalColor = mSettingsDialog->foregroundColor(); + mPlotter->alarmColor = mSettingsDialog->alarmColor(); + mPlotter->backgroundColor = mSettingsDialog->backgroundColor(); + mPlotter->fontSize = mSettingsDialog->fontSize(); + + QValueList< QStringList > list = mSettingsDialog->sensors(); + QValueList< QStringList >::Iterator it; + + for ( uint i = 0; i < sensors().count(); i++ ) { + bool found = false; + for ( it = list.begin(); it != list.end(); ++it ) { + if ( (*it)[ 0 ] == sensors().at( i )->hostName() && + (*it)[ 1 ] == KSGRD::SensorMgr->translateSensor( sensors().at( i )->name() ) ) { + mPlotter->footers[ i ] = (*it)[ 2 ]; + found = true; + break; + } + } + + if ( !found ) + removeSensor( i ); + } + + repaint(); + setModified( true ); +} + +void DancingBars::applyStyle() +{ + mPlotter->normalColor = KSGRD::Style->firstForegroundColor(); + mPlotter->alarmColor = KSGRD::Style->alarmColor(); + mPlotter->backgroundColor = KSGRD::Style->backgroundColor(); + mPlotter->fontSize = KSGRD::Style->fontSize(); + + repaint(); + setModified( true ); +} + +bool DancingBars::addSensor( const QString &hostName, const QString &name, + const QString &type, const QString &title ) +{ + if ( type != "integer" && type != "float" ) + return false; + + if ( mBars >= 32 ) + return false; + + if ( !mPlotter->addBar( title ) ) + return false; + + registerSensor( new KSGRD::SensorProperties( hostName, name, type, title ) ); + + /* To differentiate between answers from value requests and info + * requests we add 100 to the beam index for info requests. */ + sendRequest( hostName, name + "?", mBars + 100 ); + ++mBars; + mSampleBuffer.resize( mBars ); + + QString tooltip; + for ( uint i = 0; i < mBars; ++i ) { + tooltip += QString( "%1%2:%3" ).arg( i != 0 ? "\n" : "" ) + .arg( sensors().at( i )->hostName() ) + .arg( sensors().at( i )->name() ); + } + QToolTip::remove( mPlotter ); + QToolTip::add( mPlotter, tooltip ); + + return true; +} + +bool DancingBars::removeSensor( uint pos ) +{ + if ( pos >= mBars ) { + kdDebug(1215) << "DancingBars::removeSensor: idx out of range (" + << pos << ")" << endl; + return false; + } + + mPlotter->removeBar( pos ); + mBars--; + KSGRD::SensorDisplay::removeSensor( pos ); + + QString tooltip; + for ( uint i = 0; i < mBars; ++i ) { + tooltip += QString( "%1%2:%3" ).arg( i != 0 ? "\n" : "" ) + .arg( sensors().at( i )->hostName() ) + .arg( sensors().at( i )->name() ); + } + QToolTip::remove( mPlotter ); + QToolTip::add( mPlotter, tooltip ); + + return true; +} + +void DancingBars::updateSamples( const QMemArray<double> &samples ) +{ + mPlotter->updateSamples( samples ); +} + +void DancingBars::resizeEvent( QResizeEvent* ) +{ + if ( noFrame() ) + mPlotter->setGeometry( 0, 0, width(), height() ); + else + frame()->setGeometry( 0, 0, width(), height() ); +} + +QSize DancingBars::sizeHint() +{ + if ( noFrame() ) + return ( mPlotter->sizeHint() ); + else + return ( frame()->sizeHint() ); +} + +void DancingBars::answerReceived( int id, const QString &answer ) +{ + /* We received something, so the sensor is probably ok. */ + sensorError( id, false ); + + if ( id < 100 ) { + mSampleBuffer[ id ] = answer.toDouble(); + if ( mFlags.testBit( id ) == true ) { + kdDebug(1215) << "ERROR: DancingBars lost sample (" << mFlags + << ", " << mBars << ")" << endl; + sensorError( id, true ); + } + mFlags.setBit( id, true ); + + bool allBitsAvailable = true; + for ( uint i = 0; i < mBars; ++i ) + allBitsAvailable &= mFlags.testBit( i ); + + if ( allBitsAvailable ) { + mPlotter->updateSamples( mSampleBuffer ); + mFlags.fill( false ); + } + } else if ( id >= 100 ) { + KSGRD::SensorIntegerInfo info( answer ); + if ( id == 100 ) + if ( mPlotter->getMin() == 0.0 && mPlotter->getMax() == 0.0 ) { + /* We only use this information from the sensor when the + * display is still using the default values. If the + * sensor has been restored we don't touch the already set + * values. */ + mPlotter->changeRange( info.min(), info.max() ); + } + + sensors().at( id - 100 )->setUnit( info.unit() ); + } +} + +bool DancingBars::restoreSettings( QDomElement &element ) +{ + SensorDisplay::restoreSettings( element ); + + mPlotter->changeRange( element.attribute( "min", "0" ).toDouble(), + element.attribute( "max", "0" ).toDouble() ); + + mPlotter->setLimits( element.attribute( "lowlimit", "0" ).toDouble(), + element.attribute( "lowlimitactive", "0" ).toInt(), + element.attribute( "uplimit", "0" ).toDouble(), + element.attribute( "uplimitactive", "0" ).toInt() ); + + mPlotter->normalColor = restoreColor( element, "normalColor", + KSGRD::Style->firstForegroundColor() ); + mPlotter->alarmColor = restoreColor( element, "alarmColor", + KSGRD::Style->alarmColor() ); + mPlotter->backgroundColor = restoreColor( element, "backgroundColor", + KSGRD::Style->backgroundColor() ); + mPlotter->fontSize = element.attribute( "fontSize", QString( "%1" ).arg( + KSGRD::Style->fontSize() ) ).toInt(); + + QDomNodeList dnList = element.elementsByTagName( "beam" ); + for ( uint i = 0; i < dnList.count(); ++i ) { + QDomElement el = dnList.item( i ).toElement(); + addSensor( el.attribute( "hostName" ), el.attribute( "sensorName" ), + ( el.attribute( "sensorType" ).isEmpty() ? "integer" : + el.attribute( "sensorType" ) ), el.attribute( "sensorDescr" ) ); + } + + setModified( false ); + + return true; +} + +bool DancingBars::saveSettings( QDomDocument &doc, QDomElement &element, + bool save ) +{ + element.setAttribute( "min", mPlotter->getMin() ); + element.setAttribute( "max", mPlotter->getMax() ); + double l, u; + bool la, ua; + mPlotter->getLimits( l, la, u, ua ); + element.setAttribute( "lowlimit", l ); + element.setAttribute( "lowlimitactive", la ); + element.setAttribute( "uplimit", u ); + element.setAttribute( "uplimitactive", ua ); + + saveColor( element, "normalColor", mPlotter->normalColor ); + saveColor( element, "alarmColor", mPlotter->alarmColor ); + saveColor( element, "backgroundColor", mPlotter->backgroundColor ); + element.setAttribute( "fontSize", mPlotter->fontSize ); + + for ( uint i = 0; i < mBars; ++i ) { + QDomElement beam = doc.createElement( "beam" ); + element.appendChild( beam ); + beam.setAttribute( "hostName", sensors().at( i )->hostName() ); + beam.setAttribute( "sensorName", sensors().at( i )->name() ); + beam.setAttribute( "sensorType", sensors().at( i )->type() ); + beam.setAttribute( "sensorDescr", mPlotter->footers[ i ] ); + } + + SensorDisplay::saveSettings( doc, element ); + + if ( save ) + setModified( false ); + + return true; +} + +bool DancingBars::hasSettingsDialog() const +{ + return true; +} + +#include "DancingBars.moc" diff --git a/ksysguard/gui/SensorDisplayLib/DancingBars.h b/ksysguard/gui/SensorDisplayLib/DancingBars.h new file mode 100644 index 000000000..ad671dfe7 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DancingBars.h @@ -0,0 +1,90 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_DANCINGBARS_H +#define KSG_DANCINGBARS_H + +#include <SensorDisplay.h> +#include <qbitarray.h> + +class KIntNumInput; + +class QGroupBox; +class QLineEdit; +class QListViewItem; + +class BarGraph; +class DancingBarsSettings; + +class DancingBars : public KSGRD::SensorDisplay +{ + Q_OBJECT + + public: + DancingBars( QWidget *parent = 0, const char *name = 0, + const QString &title = QString::null, int min = 0, + int max = 100, bool noFrame = false, bool isApplet = false ); + virtual ~DancingBars(); + + void configureSettings(); + + bool addSensor( const QString &hostName, const QString &name, + const QString &type, const QString &title ); + bool removeSensor( uint pos ); + + void updateSamples( const QMemArray<double> &samples ); + + virtual QSize sizeHint(); + + virtual void answerReceived( int id, const QString &answer ); + + bool restoreSettings( QDomElement& ); + bool saveSettings( QDomDocument&, QDomElement&, bool save = true ); + + virtual bool hasSettingsDialog() const; + + public slots: + void applySettings(); + virtual void applyStyle(); + + protected: + virtual void resizeEvent( QResizeEvent* ); + + private: + uint mBars; + + BarGraph* mPlotter; + + DancingBarsSettings* mSettingsDialog; + + /** + The sample buffer and the flags are needed to store the incoming + samples for each beam until all samples of the period have been + received. The flags variable is used to ensure that all samples have + been received. + */ + QMemArray<double> mSampleBuffer; + QBitArray mFlags; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/DancingBarsSettings.cc b/ksysguard/gui/SensorDisplayLib/DancingBarsSettings.cc new file mode 100644 index 000000000..15e6b6ec3 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DancingBarsSettings.cc @@ -0,0 +1,398 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <kaccelmanager.h> +#include <kcolorbutton.h> +#include <klineedit.h> +#include <kinputdialog.h> +#include <klistview.h> +#include <klocale.h> +#include <knuminput.h> + +#include <qcheckbox.h> +#include <qframe.h> +#include <qgroupbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <qwhatsthis.h> + +#include "DancingBarsSettings.h" + +DancingBarsSettings::DancingBarsSettings( QWidget* parent, const char* name ) + : KDialogBase( Tabbed, i18n( "Edit BarGraph Preferences" ), + Ok | Apply | Cancel, Ok, parent, name, true, true ) +{ + // Range page + QFrame *page = addPage( i18n( "Range" ) ); + QGridLayout *pageLayout = new QGridLayout( page, 3, 1, 0, spacingHint() ); + + QGroupBox *groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Title" ), page ); + QGridLayout *boxLayout = new QGridLayout( groupBox->layout(), 1, 1 ); + + mTitle = new KLineEdit( groupBox ); + QWhatsThis::add( mTitle, i18n( "Enter the title of the display here." ) ); + boxLayout->addWidget( mTitle, 0, 0 ); + + pageLayout->addWidget( groupBox, 0, 0 ); + + groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Display Range" ), page ); + boxLayout = new QGridLayout( groupBox->layout(), 1, 5 ); + boxLayout->setColStretch( 2, 1 ); + + QLabel *label = new QLabel( i18n( "Minimum value:" ), groupBox ); + boxLayout->addWidget( label, 0, 0 ); + + mMinValue = new KDoubleSpinBox( 0, 100, 0.5, 0, 2, groupBox ); + QWhatsThis::add( mMinValue, i18n( "Enter the minimum value for the display here. If both values are 0, automatic range detection is enabled." ) ); + boxLayout->addWidget( mMinValue, 0, 1 ); + label->setBuddy( mMinValue ); + + label = new QLabel( i18n( "Maximum value:" ), groupBox ); + boxLayout->addWidget( label, 0, 3 ); + + mMaxValue = new KDoubleSpinBox( 0, 10000, 0.5, 100, 2, groupBox ); + QWhatsThis::add( mMaxValue, i18n( "Enter the maximum value for the display here. If both values are 0, automatic range detection is enabled." ) ); + boxLayout->addWidget( mMaxValue, 0, 4 ); + label->setBuddy( mMaxValue ); + + pageLayout->addWidget( groupBox, 1, 0 ); + + pageLayout->setRowStretch( 2, 1 ); + + // Alarm page + page = addPage( i18n( "Alarms" ) ); + pageLayout = new QGridLayout( page, 3, 1, 0, spacingHint() ); + + groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Alarm for Minimum Value" ), page ); + boxLayout = new QGridLayout( groupBox->layout(), 1, 4 ); + boxLayout->setColStretch( 1, 1 ); + + mUseLowerLimit = new QCheckBox( i18n( "Enable alarm" ), groupBox ); + QWhatsThis::add( mUseLowerLimit, i18n( "Enable the minimum value alarm." ) ); + boxLayout->addWidget( mUseLowerLimit, 0, 0 ); + + label = new QLabel( i18n( "Lower limit:" ), groupBox ); + boxLayout->addWidget( label, 0, 2 ); + + mLowerLimit = new KDoubleSpinBox( 0, 100, 0.5, 0, 2, groupBox ); + mLowerLimit->setEnabled( false ); + boxLayout->addWidget( mLowerLimit, 0, 3 ); + label->setBuddy( mLowerLimit ); + + pageLayout->addWidget( groupBox, 0, 0 ); + + groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Alarm for Maximum Value" ), page ); + boxLayout = new QGridLayout( groupBox->layout(), 1, 4 ); + boxLayout->setColStretch( 1, 1 ); + + mUseUpperLimit = new QCheckBox( i18n( "Enable alarm" ), groupBox ); + QWhatsThis::add( mUseUpperLimit, i18n( "Enable the maximum value alarm." ) ); + boxLayout->addWidget( mUseUpperLimit, 0, 0 ); + + label = new QLabel( i18n( "Upper limit:" ), groupBox ); + boxLayout->addWidget( label, 0, 2 ); + + mUpperLimit = new KDoubleSpinBox( 0, 100, 0.5, 0, 2, groupBox ); + mUpperLimit->setEnabled( false ); + boxLayout->addWidget( mUpperLimit, 0, 3 ); + label->setBuddy( mUpperLimit ); + + pageLayout->addWidget( groupBox, 1, 0 ); + + pageLayout->setRowStretch( 2, 1 ); + + // Look page + page = addPage( i18n( "Look" ) ); + pageLayout = new QGridLayout( page, 5, 2, 0, spacingHint() ); + + label = new QLabel( i18n( "Normal bar color:" ), page ); + pageLayout->addWidget( label, 0, 0 ); + + mForegroundColor = new KColorButton( page ); + pageLayout->addWidget( mForegroundColor, 0, 1 ); + label->setBuddy( mForegroundColor ); + + label = new QLabel( i18n( "Out-of-range color:" ), page ); + pageLayout->addWidget( label, 1, 0 ); + + mAlarmColor = new KColorButton( page ); + pageLayout->addWidget( mAlarmColor, 1, 1 ); + label->setBuddy( mAlarmColor ); + + label = new QLabel( i18n( "Background color:" ), page ); + pageLayout->addWidget( label, 2, 0 ); + + mBackgroundColor = new KColorButton( page ); + pageLayout->addWidget( mBackgroundColor, 2, 1 ); + label->setBuddy( mBackgroundColor ); + + label = new QLabel( i18n( "Font size:" ), page ); + pageLayout->addWidget( label, 3, 0 ); + + mFontSize = new KIntNumInput( 9, page ); + QWhatsThis::add( mFontSize, i18n( "This determines the size of the font used to print a label underneath the bars. Bars are automatically suppressed if text becomes too large, so it is advisable to use a small font size here." ) ); + pageLayout->addWidget( mFontSize, 3, 1 ); + label->setBuddy( mFontSize ); + + pageLayout->setRowStretch( 4, 1 ); + + // Sensor page + page = addPage( i18n( "Sensors" ) ); + pageLayout = new QGridLayout( page, 3, 2, 0, spacingHint() ); + pageLayout->setRowStretch( 2, 1 ); + + mSensorView = new KListView( page ); + mSensorView->addColumn( i18n( "Host" ) ); + mSensorView->addColumn( i18n( "Sensor" ) ); + mSensorView->addColumn( i18n( "Label" ) ); + mSensorView->addColumn( i18n( "Unit" ) ); + mSensorView->addColumn( i18n( "Status" ) ); + mSensorView->setAllColumnsShowFocus( true ); + pageLayout->addMultiCellWidget( mSensorView, 0, 2, 0, 0 ); + + mEditButton = new QPushButton( i18n( "Edit..." ), page ); + mEditButton->setEnabled( false ); + QWhatsThis::add( mEditButton, i18n( "Push this button to configure the label." ) ); + pageLayout->addWidget( mEditButton, 0, 1 ); + + mRemoveButton = new QPushButton( i18n( "Delete" ), page ); + mRemoveButton->setEnabled( false ); + QWhatsThis::add( mRemoveButton, i18n( "Push this button to delete the sensor." ) ); + pageLayout->addWidget( mRemoveButton, 1, 1 ); + + connect( mUseLowerLimit, SIGNAL( toggled( bool ) ), + mLowerLimit, SLOT( setEnabled( bool ) ) ); + connect( mUseUpperLimit, SIGNAL( toggled( bool ) ), + mUpperLimit, SLOT( setEnabled( bool ) ) ); + + connect( mSensorView, SIGNAL( selectionChanged( QListViewItem* ) ), + SLOT( selectionChanged( QListViewItem* ) ) ); + connect( mEditButton, SIGNAL( clicked() ), SLOT( editSensor() ) ); + connect( mRemoveButton, SIGNAL( clicked() ), SLOT( removeSensor() ) ); + + KAcceleratorManager::manage( this ); + + mTitle->setFocus(); +} + +DancingBarsSettings::~DancingBarsSettings() +{ +} + +void DancingBarsSettings::setTitle( const QString& title ) +{ + mTitle->setText( title ); +} + +QString DancingBarsSettings::title() const +{ + return mTitle->text(); +} + +void DancingBarsSettings::setMinValue( double min ) +{ + mMinValue->setValue( min ); +} + +double DancingBarsSettings::minValue() const +{ + return mMinValue->value(); +} + +void DancingBarsSettings::setMaxValue( double max ) +{ + mMaxValue->setValue( max ); +} + +double DancingBarsSettings::maxValue() const +{ + return mMaxValue->value(); +} + +void DancingBarsSettings::setUseLowerLimit( bool value ) +{ + mUseLowerLimit->setChecked( value ); +} + +bool DancingBarsSettings::useLowerLimit() const +{ + return mUseLowerLimit->isChecked(); +} + +void DancingBarsSettings::setLowerLimit( double limit ) +{ + mLowerLimit->setValue( limit ); +} + +double DancingBarsSettings::lowerLimit() const +{ + return mLowerLimit->value(); +} + +void DancingBarsSettings::setUseUpperLimit( bool value ) +{ + mUseUpperLimit->setChecked( value ); +} + +bool DancingBarsSettings::useUpperLimit() const +{ + return mUseUpperLimit->isChecked(); +} + +void DancingBarsSettings::setUpperLimit( double limit ) +{ + mUpperLimit->setValue( limit ); +} + +double DancingBarsSettings::upperLimit() const +{ + return mUpperLimit->value(); +} + +void DancingBarsSettings::setForegroundColor( const QColor &color ) +{ + mForegroundColor->setColor( color ); +} + +QColor DancingBarsSettings::foregroundColor() const +{ + return mForegroundColor->color(); +} + +void DancingBarsSettings::setAlarmColor( const QColor &color ) +{ + mAlarmColor->setColor( color ); +} + +QColor DancingBarsSettings::alarmColor() const +{ + return mAlarmColor->color(); +} + +void DancingBarsSettings::setBackgroundColor( const QColor &color ) +{ + mBackgroundColor->setColor( color ); +} + +QColor DancingBarsSettings::backgroundColor() const +{ + return mBackgroundColor->color(); +} + +void DancingBarsSettings::setFontSize( int size ) +{ + mFontSize->setValue( size ); +} + +int DancingBarsSettings::fontSize() const +{ + return mFontSize->value(); +} + +void DancingBarsSettings::setSensors( const QValueList< QStringList > &list ) +{ + mSensorView->clear(); + + QValueList< QStringList >::ConstIterator it; + for ( it = list.begin(); it != list.end(); ++it ) { + new QListViewItem( mSensorView, + (*it)[ 0 ], // host name + (*it)[ 1 ], // sensor name + (*it)[ 2 ], // footer title + (*it)[ 3 ], // unit + (*it)[ 4 ] ); // status + } +} + +QValueList< QStringList > DancingBarsSettings::sensors() const +{ + QValueList< QStringList > list; + + QListViewItemIterator it( mSensorView ); + while ( it.current() && !it.current()->text( 0 ).isEmpty() ) { + QStringList entry; + entry << it.current()->text( 0 ); + entry << it.current()->text( 1 ); + entry << it.current()->text( 2 ); + entry << it.current()->text( 3 ); + entry << it.current()->text( 4 ); + + list.append( entry ); + ++it; + } + + return list; +} + +void DancingBarsSettings::editSensor() +{ + QListViewItem *lvi = mSensorView->currentItem(); + + if ( !lvi ) + return; + + bool ok; + QString str = KInputDialog::getText( i18n( "Label of Bar Graph" ), + i18n( "Enter new label:" ), lvi->text( 2 ), &ok, this ); + if ( ok ) + lvi->setText( 2, str ); +} + +void DancingBarsSettings::removeSensor() +{ + QListViewItem *lvi = mSensorView->currentItem(); + + if ( lvi ) { + /* Before we delete the currently selected item, we determine a + * new item to be selected. That way we can ensure that multiple + * items can be deleted without forcing the user to select a new + * item between the deletes. If all items are deleted, the buttons + * are disabled again. */ + QListViewItem* newSelected = 0; + if ( lvi->itemBelow() ) { + lvi->itemBelow()->setSelected( true ); + newSelected = lvi->itemBelow(); + } else if ( lvi->itemAbove() ) { + lvi->itemAbove()->setSelected( true ); + newSelected = lvi->itemAbove(); + } else + selectionChanged( 0 ); + + delete lvi; + + if ( newSelected ) + mSensorView->ensureItemVisible( newSelected ); + } +} + +void DancingBarsSettings::selectionChanged( QListViewItem* lvi ) +{ + bool state = ( lvi != 0 ); + + mEditButton->setEnabled( state ); + mRemoveButton->setEnabled( state ); +} + + +#include "DancingBarsSettings.moc" diff --git a/ksysguard/gui/SensorDisplayLib/DancingBarsSettings.h b/ksysguard/gui/SensorDisplayLib/DancingBarsSettings.h new file mode 100644 index 000000000..12e559dc0 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DancingBarsSettings.h @@ -0,0 +1,106 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_DANCINGBARSSETTINGS_H +#define KSG_DANCINGBARSSETTINGS_H + +#include <kdialogbase.h> + +class KColorButton; +class KDoubleSpinBox; +class KIntNumInput; +class KLineEdit; +class KListView; + +class QCheckBox; +class QListViewItem; +class QPushButton; + +class DancingBarsSettings : public KDialogBase +{ + Q_OBJECT + + public: + DancingBarsSettings( QWidget* parent = 0, const char* name = 0 ); + ~DancingBarsSettings(); + + void setTitle( const QString& title ); + QString title() const; + + void setMinValue( double min ); + double minValue() const; + + void setMaxValue( double max ); + double maxValue() const; + + void setUseLowerLimit( bool value ); + bool useLowerLimit() const; + + void setLowerLimit( double limit ); + double lowerLimit() const; + + void setUseUpperLimit( bool value ); + bool useUpperLimit() const; + + void setUpperLimit( double limit ); + double upperLimit() const; + + void setForegroundColor( const QColor &color ); + QColor foregroundColor() const; + + void setAlarmColor( const QColor &color ); + QColor alarmColor() const; + + void setBackgroundColor( const QColor &color ); + QColor backgroundColor() const; + + void setFontSize( int size ); + int fontSize() const; + + void setSensors( const QValueList< QStringList > &list ); + QValueList< QStringList > sensors() const; + + private slots: + void editSensor(); + void removeSensor(); + void selectionChanged( QListViewItem* ); + + private: + KColorButton *mForegroundColor; + KColorButton *mAlarmColor; + KColorButton *mBackgroundColor; + KDoubleSpinBox *mMinValue; + KDoubleSpinBox *mMaxValue; + KDoubleSpinBox *mLowerLimit; + KDoubleSpinBox *mUpperLimit; + KLineEdit *mTitle; + KListView *mSensorView; + KIntNumInput *mFontSize; + + QCheckBox *mUseLowerLimit; + QCheckBox *mUseUpperLimit; + QPushButton *mEditButton; + QPushButton *mRemoveButton; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/DummyDisplay.cc b/ksysguard/gui/SensorDisplayLib/DummyDisplay.cc new file mode 100644 index 000000000..a4ea6afb4 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DummyDisplay.cc @@ -0,0 +1,58 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000, 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <klocale.h> +#include <ksgrd/SensorManager.h> + +#include <qwhatsthis.h> + +#include "DummyDisplay.h" + +DummyDisplay::DummyDisplay( QWidget* parent, const char* name, + const QString&, double, double ) + : KSGRD::SensorDisplay( parent, name, i18n( "Drop Sensor Here" ) ) +{ + setMinimumSize( 16, 16 ); + + QWhatsThis::add( this, i18n( + "This is an empty space in a worksheet. Drag a sensor from " + "the Sensor Browser and drop it here. A sensor display will " + "appear that allows you to monitor the values of the sensor " + "over time." ) ); +} + +void DummyDisplay::resizeEvent( QResizeEvent* ) +{ + frame()->setGeometry( 0, 0, width(), height() ); +} + +bool DummyDisplay::eventFilter( QObject* object, QEvent* event ) +{ + if ( event->type() == QEvent::MouseButtonRelease && + ( (QMouseEvent*)event)->button() == LeftButton ) + setFocus(); + + return QWidget::eventFilter( object, event ); +} + +#include "DummyDisplay.moc" diff --git a/ksysguard/gui/SensorDisplayLib/DummyDisplay.h b/ksysguard/gui/SensorDisplayLib/DummyDisplay.h new file mode 100644 index 000000000..53098fa0c --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/DummyDisplay.h @@ -0,0 +1,44 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_DUMMYDISPLAY_H +#define KSG_DUMMYDISPLAY_H + +#include <SensorDisplay.h> + +class DummyDisplay : public KSGRD::SensorDisplay +{ + Q_OBJECT + + public: + DummyDisplay( QWidget* parent = 0, const char* name = 0, + const QString& = QString::null, double min = 0, + double max = 0 ); + virtual ~DummyDisplay() {} + + void resizeEvent( QResizeEvent* ); + + virtual bool eventFilter( QObject*, QEvent* ); +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/FancyPlotter.cc b/ksysguard/gui/SensorDisplayLib/FancyPlotter.cc new file mode 100644 index 000000000..361ce16e7 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/FancyPlotter.cc @@ -0,0 +1,457 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <qdom.h> +#include <qimage.h> +#include <qtooltip.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> + +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> +#include "SensorDisplay.h" +#include "FancyPlotterSettings.h" + +#include "FancyPlotter.h" + +FancyPlotter::FancyPlotter( QWidget* parent, const char* name, + const QString &title, double, double, + bool nf, bool isApplet) + : KSGRD::SensorDisplay( parent, name, title, nf, isApplet ) +{ + mBeams = 0; + mSettingsDialog = 0; + + if ( noFrame() ) { + mPlotter = new SignalPlotter( this ); + mPlotter->setShowTopBar( true ); + } else + mPlotter = new SignalPlotter( frame() ); + mPlotter->setTitle( title ); + mPlotter->setThinFrame(!isApplet); //if we aren't an applet, draw a thin white frame on the left and bottom, for a 3d effect + + setMinimumSize( sizeHint() ); + + /* All RMB clicks to the mPlotter widget will be handled by + * SensorDisplay::eventFilter. */ + mPlotter->installEventFilter( this ); + + setPlotterWidget( mPlotter ); + + setModified( false ); +} + +FancyPlotter::~FancyPlotter() +{ +} + +void FancyPlotter::configureSettings() +{ + if(mSettingsDialog) { + return; + } + mSettingsDialog = new FancyPlotterSettings( this ); + + mSettingsDialog->setTitle( title() ); + mSettingsDialog->setUseAutoRange( mPlotter->useAutoRange() ); + mSettingsDialog->setMinValue( mPlotter->minValue() ); + mSettingsDialog->setMaxValue( mPlotter->maxValue() ); + + mSettingsDialog->setUsePolygonStyle( mPlotter->graphStyle() == GRAPH_POLYGON ); + mSettingsDialog->setHorizontalScale( mPlotter->horizontalScale() ); + + mSettingsDialog->setShowVerticalLines( mPlotter->showVerticalLines() ); + mSettingsDialog->setVerticalLinesColor( mPlotter->verticalLinesColor() ); + mSettingsDialog->setVerticalLinesDistance( mPlotter->verticalLinesDistance() ); + mSettingsDialog->setVerticalLinesScroll( mPlotter->verticalLinesScroll() ); + + mSettingsDialog->setShowHorizontalLines( mPlotter->showHorizontalLines() ); + mSettingsDialog->setHorizontalLinesColor( mPlotter->horizontalLinesColor() ); + mSettingsDialog->setHorizontalLinesCount( mPlotter->horizontalLinesCount() ); + + mSettingsDialog->setShowLabels( mPlotter->showLabels() ); + mSettingsDialog->setShowTopBar( mPlotter->showTopBar() ); + mSettingsDialog->setFontSize( mPlotter->fontSize() ); + + mSettingsDialog->setBackgroundColor( mPlotter->backgroundColor() ); + + QValueList< QStringList > list; + for ( uint i = 0; i < mBeams; ++i ) { + QStringList entry; + entry << QString::number(i); + entry << sensors().at( i )->hostName(); + entry << KSGRD::SensorMgr->translateSensor( sensors().at( i )->name() ); + entry << KSGRD::SensorMgr->translateUnit( sensors().at( i )->unit() ); + entry << ( sensors().at( i )->isOk() ? i18n( "OK" ) : i18n( "Error" ) ); + entry << ( mPlotter->beamColors()[ i ].name() ); + + list.append( entry ); + } + mSettingsDialog->setSensors( list ); + + connect( mSettingsDialog, SIGNAL( applyClicked() ), SLOT( applySettings() ) ); + connect( mSettingsDialog, SIGNAL( okClicked() ), SLOT( applySettings() ) ); + connect( mSettingsDialog, SIGNAL( finished() ), SLOT( killDialog() ) ); + + mSettingsDialog->show(); +} + +void FancyPlotter::killDialog() { + mSettingsDialog->delayedDestruct(); + mSettingsDialog = 0; +} + +void FancyPlotter::applySettings() +{ + setTitle( mSettingsDialog->title() ); + mPlotter->setTitle( title() ); + + if ( mSettingsDialog->useAutoRange() ) + mPlotter->setUseAutoRange( true ); + else { + mPlotter->setUseAutoRange( false ); + mPlotter->changeRange( 0, mSettingsDialog->minValue(), + mSettingsDialog->maxValue() ); + } + + if ( mSettingsDialog->usePolygonStyle() ) + mPlotter->setGraphStyle( GRAPH_POLYGON ); + else + mPlotter->setGraphStyle( GRAPH_ORIGINAL ); + + if ( mPlotter->horizontalScale() != mSettingsDialog->horizontalScale() ) { + mPlotter->setHorizontalScale( mSettingsDialog->horizontalScale() ); + // Can someone think of a useful QResizeEvent to pass? + // It doesn't really matter anyway because it's not used. + emit resizeEvent( 0 ); + } + + mPlotter->setShowVerticalLines( mSettingsDialog->showVerticalLines() ); + mPlotter->setVerticalLinesColor( mSettingsDialog->verticalLinesColor() ); + mPlotter->setVerticalLinesDistance( mSettingsDialog->verticalLinesDistance() ); + mPlotter->setVerticalLinesScroll( mSettingsDialog->verticalLinesScroll() ); + + mPlotter->setShowHorizontalLines( mSettingsDialog->showHorizontalLines() ); + mPlotter->setHorizontalLinesColor( mSettingsDialog->horizontalLinesColor() ); + mPlotter->setHorizontalLinesCount( mSettingsDialog->horizontalLinesCount() ); + + mPlotter->setShowLabels( mSettingsDialog->showLabels() ); + mPlotter->setShowTopBar( mSettingsDialog->showTopBar() ); + mPlotter->setFontSize( mSettingsDialog->fontSize() ); + + mPlotter->setBackgroundColor( mSettingsDialog->backgroundColor() ); + + + QValueList<int> orderOfSensors = mSettingsDialog->order(); + QValueList<int> deletedSensors = mSettingsDialog->deleted(); + mSettingsDialog->clearDeleted(); + mSettingsDialog->resetOrder(); + QValueList< int >::Iterator itDelete; + for ( itDelete = deletedSensors.begin(); itDelete != deletedSensors.end(); ++itDelete ) + removeSensor(*itDelete); + + QValueList< int >::Iterator itOrder; + mPlotter->reorderBeams(orderOfSensors); + reorderSensors(orderOfSensors); + + QValueList< QStringList > list = mSettingsDialog->sensors(); + QValueList< QStringList >::Iterator it; + + for ( uint i = 0; i < sensors().count(); ++i ) + mPlotter->beamColors()[ i ] = QColor( list[i][ 5 ] ); + + mPlotter->repaint(); + setModified( true ); +} + +void FancyPlotter::applyStyle() +{ + mPlotter->setVerticalLinesColor( KSGRD::Style->firstForegroundColor() ); + mPlotter->setHorizontalLinesColor( KSGRD::Style->secondForegroundColor() ); + mPlotter->setBackgroundColor( KSGRD::Style->backgroundColor() ); + mPlotter->setFontSize( KSGRD::Style->fontSize() ); + for ( uint i = 0; i < mPlotter->beamColors().count() && + i < KSGRD::Style->numSensorColors(); ++i ) + mPlotter->beamColors()[ i ] = KSGRD::Style->sensorColor( i ); + + mPlotter->update(); + setModified( true ); +} + +bool FancyPlotter::addSensor( const QString &hostName, const QString &name, + const QString &type, const QString &title ) +{ + return addSensor( hostName, name, type, title, + KSGRD::Style->sensorColor( mBeams ) ); +} + +bool FancyPlotter::addSensor( const QString &hostName, const QString &name, + const QString &type, const QString &title, + const QColor &color ) +{ + if ( type != "integer" && type != "float" ) + return false; + + if ( mBeams > 0 && hostName != sensors().at( 0 )->hostName() ) { + KMessageBox::sorry( this, QString( "All sensors of this display need " + "to be from the host %1!" ) + .arg( sensors().at( 0 )->hostName() ) ); + + /* We have to enforce this since the answers to value requests + * need to be received in order. */ + return false; + } + + if ( !mPlotter->addBeam( color ) ) + return false; + + registerSensor( new FPSensorProperties( hostName, name, type, title, color ) ); + + /* To differentiate between answers from value requests and info + * requests we add 100 to the beam index for info requests. */ + sendRequest( hostName, name + "?", mBeams + 100 ); + + ++mBeams; + + QString tooltip; + for ( uint i = 0; i < mBeams; ++i ) { + tooltip += QString( "%1%2:%3" ).arg( i != 0 ? "\n" : "" ) + .arg( sensors().at( mBeams - i - 1 )->hostName() ) + .arg( sensors().at( mBeams - i - 1 )->name() ); + } + + QToolTip::remove( mPlotter ); + QToolTip::add( mPlotter, tooltip ); + + return true; +} + +bool FancyPlotter::removeSensor( uint pos ) +{ + if ( pos >= mBeams ) { + kdDebug(1215) << "FancyPlotter::removeSensor: idx out of range (" + << pos << ")" << endl; + return false; + } + + mPlotter->removeBeam( pos ); + mBeams--; + KSGRD::SensorDisplay::removeSensor( pos ); + + QString tooltip; + for ( uint i = 0; i < mBeams; ++i ) { + tooltip += QString( "%1%2:%3" ).arg( i != 0 ? "\n" : "" ) + .arg( sensors().at( mBeams - i - 1 )->hostName() ) + .arg( sensors().at( mBeams - i - 1 )->name() ); + } + + QToolTip::remove( mPlotter ); + QToolTip::add( mPlotter, tooltip ); + + return true; +} + +void FancyPlotter::resizeEvent( QResizeEvent* ) +{ + if ( noFrame() ) + mPlotter->setGeometry( 0, 0, width(), height() ); + else + frame()->setGeometry( 0, 0, width(), height() ); +} + +QSize FancyPlotter::sizeHint() +{ + if ( noFrame() ) + return mPlotter->sizeHint(); + else + return frame()->sizeHint(); +} + +void FancyPlotter::answerReceived( int id, const QString &answer ) +{ + if ( (uint)id < mBeams ) { + if ( id != (int)mSampleBuf.count() ) { + if ( id == 0 ) + sensorError( mBeams - 1, true ); + else + sensorError( id - 1, true ); + } + mSampleBuf.append( answer.toDouble() ); + + /* We received something, so the sensor is probably ok. */ + sensorError( id, false ); + + if ( id == (int)mBeams - 1 ) { + mPlotter->addSample( mSampleBuf ); + mSampleBuf.clear(); + } + } else if ( id >= 100 ) { + KSGRD::SensorFloatInfo info( answer ); + if ( !mPlotter->useAutoRange() && mPlotter->minValue() == 0.0 && + mPlotter->maxValue() == 0.0 ) { + /* We only use this information from the sensor when the + * display is still using the default values. If the + * sensor has been restored we don't touch the already set + * values. */ + mPlotter->changeRange( id - 100, info.min(), info.max() ); + if ( info.min() == 0.0 && info.max() == 0.0 ) + mPlotter->setUseAutoRange( true ); + } + sensors().at( id - 100 )->setUnit( info.unit() ); + } +} + +bool FancyPlotter::restoreSettings( QDomElement &element ) +{ + /* autoRage was added after KDE 2.x and was brokenly emulated by + * min == 0.0 and max == 0.0. Since we have to be able to read old + * files as well we have to emulate the old behaviour as well. */ + double min = element.attribute( "min", "0.0" ).toDouble(); + double max = element.attribute( "max", "0.0" ).toDouble(); + if ( element.attribute( "autoRange", min == 0.0 && max == 0.0 ? "1" : "0" ).toInt() ) + mPlotter->setUseAutoRange( true ); + else { + mPlotter->setUseAutoRange( false ); + mPlotter->changeRange( 0, element.attribute( "min" ).toDouble(), + element.attribute( "max" ).toDouble() ); + } + + mPlotter->setShowVerticalLines( element.attribute( "vLines", "1" ).toUInt() ); + mPlotter->setVerticalLinesColor( restoreColor( element, "vColor", + KSGRD::Style->firstForegroundColor() ) ); + mPlotter->setVerticalLinesDistance( element.attribute( "vDistance", "30" ).toUInt() ); + mPlotter->setVerticalLinesScroll( element.attribute( "vScroll", "1" ).toUInt() ); + mPlotter->setGraphStyle( element.attribute( "graphStyle", "0" ).toUInt() ); + mPlotter->setHorizontalScale( element.attribute( "hScale", "1" ).toUInt() ); + + mPlotter->setShowHorizontalLines( element.attribute( "hLines", "1" ).toUInt() ); + mPlotter->setHorizontalLinesColor( restoreColor( element, "hColor", + KSGRD::Style->secondForegroundColor() ) ); + mPlotter->setHorizontalLinesCount( element.attribute( "hCount", "5" ).toUInt() ); + + mPlotter->setShowLabels( element.attribute( "labels", "1" ).toUInt() ); + mPlotter->setShowTopBar( element.attribute( "topBar", "0" ).toUInt() ); + mPlotter->setFontSize( element.attribute( "fontSize", + QString( "%1" ).arg( KSGRD::Style->fontSize() ) ).toUInt() ); + + mPlotter->setBackgroundColor( restoreColor( element, "bColor", + KSGRD::Style->backgroundColor() ) ); + + QDomNodeList dnList = element.elementsByTagName( "beam" ); + for ( uint i = 0; i < dnList.count(); ++i ) { + QDomElement el = dnList.item( i ).toElement(); + addSensor( el.attribute( "hostName" ), el.attribute( "sensorName" ), + ( el.attribute( "sensorType" ).isEmpty() ? "integer" : + el.attribute( "sensorType" ) ), "", restoreColor( el, "color", + KSGRD::Style->sensorColor( i ) ) ); + } + + SensorDisplay::restoreSettings( element ); + + if ( !title().isEmpty() ) + mPlotter->setTitle( title() ); + + setModified( false ); + + return true; +} + +bool FancyPlotter::saveSettings( QDomDocument &doc, QDomElement &element, + bool save ) +{ + element.setAttribute( "min", mPlotter->minValue() ); + element.setAttribute( "max", mPlotter->maxValue() ); + element.setAttribute( "autoRange", mPlotter->useAutoRange() ); + element.setAttribute( "vLines", mPlotter->showVerticalLines() ); + saveColor( element, "vColor", mPlotter->verticalLinesColor() ); + element.setAttribute( "vDistance", mPlotter->verticalLinesDistance() ); + element.setAttribute( "vScroll", mPlotter->verticalLinesScroll() ); + + element.setAttribute( "graphStyle", mPlotter->graphStyle() ); + element.setAttribute( "hScale", mPlotter->horizontalScale() ); + + element.setAttribute( "hLines", mPlotter->showHorizontalLines() ); + saveColor( element, "hColor", mPlotter->horizontalLinesColor() ); + element.setAttribute( "hCount", mPlotter->horizontalLinesCount() ); + + element.setAttribute( "labels", mPlotter->showLabels() ); + element.setAttribute( "topBar", mPlotter->showTopBar() ); + element.setAttribute( "fontSize", mPlotter->fontSize() ); + + saveColor( element, "bColor", mPlotter->backgroundColor() ); + + for ( uint i = 0; i < mBeams; ++i ) { + QDomElement beam = doc.createElement( "beam" ); + element.appendChild( beam ); + beam.setAttribute( "hostName", sensors().at( i )->hostName() ); + beam.setAttribute( "sensorName", sensors().at( i )->name() ); + beam.setAttribute( "sensorType", sensors().at( i )->type() ); + saveColor( beam, "color", mPlotter->beamColors()[ i ] ); + } + + SensorDisplay::saveSettings( doc, element ); + + if ( save ) + setModified( false ); + + return true; +} + +bool FancyPlotter::hasSettingsDialog() const +{ + return true; +} + + + +FPSensorProperties::FPSensorProperties() +{ +} + +FPSensorProperties::FPSensorProperties( const QString &hostName, + const QString &name, + const QString &type, + const QString &description, + const QColor &color ) + : KSGRD::SensorProperties( hostName, name, type, description ), + mColor( color ) +{ +} + +FPSensorProperties::~FPSensorProperties() +{ +} + +void FPSensorProperties::setColor( const QColor &color ) +{ + mColor = color; +} + +QColor FPSensorProperties::color() const +{ + return mColor; +} + +#include "FancyPlotter.moc" diff --git a/ksysguard/gui/SensorDisplayLib/FancyPlotter.h b/ksysguard/gui/SensorDisplayLib/FancyPlotter.h new file mode 100644 index 000000000..d19c28760 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/FancyPlotter.h @@ -0,0 +1,103 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_FANCYPLOTTER_H +#define KSG_FANCYPLOTTER_H + +#include <kdialogbase.h> + +#include <SensorDisplay.h> + +#include "SignalPlotter.h" + +class QListViewItem; +class FancyPlotterSettings; + +class FPSensorProperties : public KSGRD::SensorProperties +{ + public: + FPSensorProperties(); + FPSensorProperties( const QString &hostName, const QString &name, + const QString &type, const QString &description, + const QColor &color ); + ~FPSensorProperties(); + + void setColor( const QColor &color ); + QColor color() const; + + private: + QColor mColor; +}; + +class FancyPlotter : public KSGRD::SensorDisplay +{ + Q_OBJECT + + public: + FancyPlotter( QWidget* parent = 0, const char* name = 0, + const QString& title = QString::null, double min = 0, + double max = 100, bool noFrame = false, bool isApplet = false ); + virtual ~FancyPlotter(); + + void configureSettings(); + + bool addSensor( const QString &hostName, const QString &name, + const QString &type, const QString &title ); + bool addSensor( const QString &hostName, const QString &name, + const QString &type, const QString &title, + const QColor &color ); + + bool removeSensor( uint pos ); + + virtual QSize sizeHint(void); + + virtual void answerReceived( int id, const QString &answer ); + + virtual bool restoreSettings( QDomElement &element ); + virtual bool saveSettings( QDomDocument &doc, QDomElement &element, + bool save = true ); + + virtual bool hasSettingsDialog() const; + + public slots: + void applySettings(); + virtual void applyStyle(); + void killDialog(); + + protected: + virtual void resizeEvent( QResizeEvent* ); + + private: + uint mBeams; + + SignalPlotter* mPlotter; + + FancyPlotterSettings* mSettingsDialog; + + /** + The sample buffer and the flags are needed to store the incoming + samples for each beam until all samples of the period have been + received. The flags variable is used to ensure that all samples have + been received. + */ + QValueList<double> mSampleBuf; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/FancyPlotterSettings.cc b/ksysguard/gui/SensorDisplayLib/FancyPlotterSettings.cc new file mode 100644 index 000000000..9d4114bd3 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/FancyPlotterSettings.cc @@ -0,0 +1,637 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <kaccelmanager.h> +#include <kcolorbutton.h> +#include <kcolordialog.h> +#include <klineedit.h> +#include <klistview.h> +#include <klocale.h> +#include <knuminput.h> + +#include <qcheckbox.h> +#include <qbuttongroup.h> +#include <qgroupbox.h> +#include <qimage.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qpixmap.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <qwhatsthis.h> +#include <qheader.h> + +#include "FancyPlotterSettings.h" + +FancyPlotterSettings::FancyPlotterSettings( QWidget* parent, const char* name ) + : KDialogBase( Tabbed, i18n( "Signal Plotter Settings" ), Ok | Apply | Cancel, + Ok, parent, name, false, true ) +{ + QFrame *page = 0; + QGridLayout *pageLayout = 0; + QGridLayout *boxLayout = 0; + QGroupBox *groupBox = 0; + QLabel *label = 0; + + // Style page + page = addPage( i18n( "Style" ) ); + pageLayout = new QGridLayout( page, 3, 2, 0, spacingHint() ); + + label = new QLabel( i18n( "Title:" ), page ); + pageLayout->addWidget( label, 0, 0 ); + + mTitle = new KLineEdit( page ); + QWhatsThis::add( mTitle, i18n( "Enter the title of the display here." ) ); + pageLayout->addWidget( mTitle, 0, 1 ); + label->setBuddy( mTitle ); + + QButtonGroup *buttonBox = new QButtonGroup( 2, Qt::Vertical, + i18n( "Graph Drawing Style" ), page ); + + mUsePolygonStyle = new QRadioButton( i18n( "Basic polygons" ), buttonBox ); + mUsePolygonStyle->setChecked( true ); + mUseOriginalStyle = new QRadioButton( i18n( "Original - single line per data point" ), buttonBox ); + + pageLayout->addMultiCellWidget( buttonBox, 1, 1, 0, 1 ); + + // Scales page + page = addPage( i18n( "Scales" ) ); + pageLayout = new QGridLayout( page, 2, 1, 0, spacingHint() ); + + groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Vertical Scale" ), page ); + boxLayout = new QGridLayout( groupBox->layout(), 2, 5, spacingHint() ); + boxLayout->setColStretch( 2, 1 ); + + mUseAutoRange = new QCheckBox( i18n( "Automatic range detection" ), groupBox ); + QWhatsThis::add( mUseAutoRange, i18n( "Check this box if you want the display range to adapt dynamically to the currently displayed values; if you do not check this, you have to specify the range you want in the fields below." ) ); + boxLayout->addMultiCellWidget( mUseAutoRange, 0, 0, 0, 4 ); + + label = new QLabel( i18n( "Minimum value:" ), groupBox ); + boxLayout->addWidget( label, 1, 0 ); + + mMinValue = new KLineEdit( groupBox ); + mMinValue->setAlignment( AlignRight ); + mMinValue->setEnabled( false ); + QWhatsThis::add( mMinValue, i18n( "Enter the minimum value for the display here. If both values are 0, automatic range detection is enabled." ) ); + boxLayout->addWidget( mMinValue, 1, 1 ); + label->setBuddy( mMinValue ); + + label = new QLabel( i18n( "Maximum value:" ), groupBox ); + boxLayout->addWidget( label, 1, 3 ); + + mMaxValue = new KLineEdit( groupBox ); + mMaxValue->setAlignment( AlignRight ); + mMaxValue->setEnabled( false ); + QWhatsThis::add( mMaxValue, i18n( "Enter the maximum value for the display here. If both values are 0, automatic range detection is enabled." ) ); + boxLayout->addWidget( mMaxValue, 1, 4 ); + label->setBuddy( mMaxValue ); + + pageLayout->addWidget( groupBox, 0, 0 ); + + groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Horizontal Scale" ), page ); + boxLayout = new QGridLayout( groupBox->layout(), 2, 2, spacingHint() ); + boxLayout->setRowStretch( 1, 1 ); + + mHorizontalScale = new KIntNumInput( 1, groupBox ); + mHorizontalScale->setMinValue( 1 ); + mHorizontalScale->setMaxValue( 50 ); + boxLayout->addWidget( mHorizontalScale, 0, 0 ); + + label = new QLabel( i18n( "pixel(s) per time period" ), groupBox ); + boxLayout->addWidget( label, 0, 1 ); + + pageLayout->addWidget( groupBox, 1, 0 ); + + // Grid page + page = addPage( i18n( "Grid" ) ); + pageLayout = new QGridLayout( page, 3, 2, 0, spacingHint() ); + + groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Lines" ), page ); + boxLayout = new QGridLayout( groupBox->layout(), 2, 5, spacingHint() ); + boxLayout->setColStretch( 1, 1 ); + + mShowVerticalLines = new QCheckBox( i18n( "Vertical lines" ), groupBox ); + QWhatsThis::add( mShowVerticalLines, i18n( "Check this to activate the vertical lines if display is large enough." ) ); + boxLayout->addWidget( mShowVerticalLines, 0, 0 ); + + label = new QLabel( i18n( "Distance:" ), groupBox ); + boxLayout->addWidget( label, 0, 2 ); + + mVerticalLinesDistance = new KIntNumInput( 0, groupBox ); + mVerticalLinesDistance->setMinValue( 10 ); + mVerticalLinesDistance->setMaxValue( 120 ); + QWhatsThis::add( mVerticalLinesDistance, i18n( "Enter the distance between two vertical lines here." ) ); + boxLayout->addWidget( mVerticalLinesDistance , 0, 3 ); + label->setBuddy( mVerticalLinesDistance ); + + mVerticalLinesScroll = new QCheckBox( i18n( "Vertical lines scroll" ), groupBox ); + boxLayout->addWidget( mVerticalLinesScroll, 0, 4 ); + + mShowHorizontalLines = new QCheckBox( i18n( "Horizontal lines" ), groupBox ); + QWhatsThis::add( mShowHorizontalLines, i18n( "Check this to enable horizontal lines if display is large enough." ) ); + boxLayout->addWidget( mShowHorizontalLines, 1, 0 ); + + label = new QLabel( i18n( "Count:" ), groupBox ); + boxLayout->addWidget( label, 1, 2 ); + + mHorizontalLinesCount = new KIntNumInput( 0, groupBox ); + mHorizontalLinesCount->setMinValue( 1 ); + mHorizontalLinesCount->setMaxValue( 100 ); + QWhatsThis::add( mHorizontalLinesCount, i18n( "Enter the number of horizontal lines here." ) ); + boxLayout->addWidget( mHorizontalLinesCount , 1, 3 ); + label->setBuddy( mHorizontalLinesCount ); + + boxLayout->setRowStretch( 2, 1 ); + + pageLayout->addMultiCellWidget( groupBox, 0, 0, 0, 1 ); + + groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Text" ), page ); + boxLayout = new QGridLayout( groupBox->layout(), 3, 4, spacingHint() ); + boxLayout->setColStretch( 1, 1 ); + + mShowLabels = new QCheckBox( i18n( "Labels" ), groupBox ); + QWhatsThis::add( mShowLabels, i18n( "Check this box if horizontal lines should be decorated with the values they mark." ) ); + boxLayout->addWidget( mShowLabels, 0, 0 ); + + label = new QLabel( i18n( "Font size:" ), groupBox ); + boxLayout->addWidget( label, 0, 2 ); + + mFontSize = new KIntNumInput( 9, groupBox ); + mFontSize->setMinValue( 5 ); + mFontSize->setMaxValue( 24 ); + boxLayout->addWidget( mFontSize, 0, 3 ); + label->setBuddy( mFontSize ); + + mShowTopBar = new QCheckBox( i18n( "Top bar" ), groupBox ); + QWhatsThis::add( mShowTopBar, i18n( "Check this to active the display title bar. This is probably only useful for applet displays. The bar is only visible if the display is large enough." ) ); + boxLayout->addWidget( mShowTopBar, 1, 0 ); + + boxLayout->setRowStretch( 2, 1 ); + + pageLayout->addWidget( groupBox, 1, 0 ); + + groupBox = new QGroupBox( 0, Qt::Vertical, i18n( "Colors" ), page ); + boxLayout = new QGridLayout( groupBox->layout(), 4, 2, spacingHint() ); + + label = new QLabel( i18n( "Vertical lines:" ), groupBox ); + boxLayout->addWidget( label, 0, 0 ); + + mVerticalLinesColor = new KColorButton( groupBox ); + boxLayout->addWidget( mVerticalLinesColor, 0, 1 ); + label->setBuddy( mVerticalLinesColor ); + + label = new QLabel( i18n( "Horizontal lines:" ), groupBox ); + boxLayout->addWidget( label, 1, 0 ); + + mHorizontalLinesColor = new KColorButton( groupBox ); + boxLayout->addWidget( mHorizontalLinesColor, 1, 1 ); + label->setBuddy( mHorizontalLinesColor ); + + label = new QLabel( i18n( "Background:" ), groupBox ); + boxLayout->addWidget( label, 2, 0 ); + + mBackgroundColor = new KColorButton( groupBox ); + boxLayout->addWidget( mBackgroundColor, 2, 1 ); + label->setBuddy( mBackgroundColor ); + + boxLayout->setRowStretch( 3, 1 ); + + pageLayout->addWidget( groupBox, 1, 1 ); + + pageLayout->setRowStretch( 2, 1 ); + + // Sensors page + page = addPage( i18n( "Sensors" ) ); + pageLayout = new QGridLayout( page, 6, 2, 0, spacingHint() ); + pageLayout->setRowStretch( 2, 1 ); + pageLayout->setRowStretch( 5, 1 ); + + mSensorView = new KListView( page ); + mSensorView->addColumn("" , 0); + mSensorView->addColumn( i18n( "Host" ) ); + mSensorView->addColumn( i18n( "Sensor" ) ); + mSensorView->addColumn( i18n( "Unit" ) ); + mSensorView->addColumn( i18n( "Status" ) ); + mSensorView->setResizeMode(QListView::LastColumn); + mSensorView->header()->setResizeEnabled(false, 0); + mSensorView->hideColumn(0); + mSensorView->header()->resizeSection(0, 0); + mSensorView->setAllColumnsShowFocus( true ); + pageLayout->addMultiCellWidget( mSensorView, 0, 5, 0, 0 ); + mSensorView->setSortColumn ( -1 ); + mEditButton = new QPushButton( i18n( "Set Color..." ), page ); + mEditButton->setEnabled( false ); + QWhatsThis::add( mEditButton, i18n( "Push this button to configure the color of the sensor in the diagram." ) ); + pageLayout->addWidget( mEditButton, 0, 1 ); + + mRemoveButton = new QPushButton( i18n( "Delete" ), page ); + mRemoveButton->setEnabled( false ); + QWhatsThis::add( mRemoveButton, i18n( "Push this button to delete the sensor." ) ); + pageLayout->addWidget( mRemoveButton, 1, 1 ); + + mMoveUpButton = new QPushButton( i18n( "Move Up" ), page ); + mMoveUpButton->setEnabled( false ); + pageLayout->addWidget( mMoveUpButton, 3, 1 ); + + mMoveDownButton = new QPushButton( i18n( "Move Down" ), page ); + mMoveDownButton->setEnabled( false ); + pageLayout->addWidget( mMoveDownButton, 4, 1 ); + + connect( mUseAutoRange, SIGNAL( toggled( bool ) ), mMinValue, + SLOT( setDisabled( bool ) ) ); + connect( mUseAutoRange, SIGNAL( toggled( bool ) ), mMaxValue, + SLOT( setDisabled( bool ) ) ); + connect( mShowVerticalLines, SIGNAL( toggled( bool ) ), mVerticalLinesDistance, + SLOT( setEnabled( bool ) ) ); + connect( mShowVerticalLines, SIGNAL( toggled( bool ) ), mVerticalLinesScroll, + SLOT( setEnabled( bool ) ) ); + connect( mShowVerticalLines, SIGNAL( toggled( bool ) ), mVerticalLinesColor, + SLOT( setEnabled( bool ) ) ); + connect( mShowHorizontalLines, SIGNAL( toggled( bool ) ), mHorizontalLinesCount, + SLOT( setEnabled( bool ) ) ); + connect( mShowHorizontalLines, SIGNAL( toggled( bool ) ), mHorizontalLinesColor, + SLOT( setEnabled( bool ) ) ); + connect( mShowHorizontalLines, SIGNAL( toggled( bool ) ), mShowLabels, + SLOT( setEnabled( bool ) ) ); + connect( mSensorView, SIGNAL( selectionChanged( QListViewItem* ) ), + SLOT( selectionChanged( QListViewItem* ) ) ); + + connect( mEditButton, SIGNAL( clicked() ), SLOT( editSensor() ) ); + connect( mRemoveButton, SIGNAL( clicked() ), SLOT( removeSensor() ) ); + connect( mMoveUpButton, SIGNAL( clicked() ), SLOT( moveUpSensor() ) ); + connect( mMoveDownButton, SIGNAL( clicked() ), SLOT( moveDownSensor() ) ); + connect ( mSensorView, SIGNAL( doubleClicked( QListViewItem *, const QPoint &, int )), SLOT(editSensor())); + + KAcceleratorManager::manage( this ); +} + +FancyPlotterSettings::~FancyPlotterSettings() +{ +} + +void FancyPlotterSettings::setTitle( const QString &title ) +{ + mTitle->setText( title ); +} + +QString FancyPlotterSettings::title() const +{ + return mTitle->text(); +} + +void FancyPlotterSettings::setUseAutoRange( bool value ) +{ + mUseAutoRange->setChecked( value ); + mMinValue->setEnabled( !value ); + mMaxValue->setEnabled( !value ); +} + +bool FancyPlotterSettings::useAutoRange() const +{ + return mUseAutoRange->isChecked(); +} + +void FancyPlotterSettings::setMinValue( double min ) +{ + mMinValue->setText( QString::number( min ) ); +} + +double FancyPlotterSettings::minValue() const +{ + return mMinValue->text().toDouble(); +} + +void FancyPlotterSettings::setMaxValue( double max ) +{ + mMaxValue->setText( QString::number( max ) ); +} + +double FancyPlotterSettings::maxValue() const +{ + return mMaxValue->text().toDouble(); +} + +void FancyPlotterSettings::setUsePolygonStyle( bool value ) +{ + if ( value ) + mUsePolygonStyle->setChecked( true ); + else + mUseOriginalStyle->setChecked( true ); +} + +bool FancyPlotterSettings::usePolygonStyle() const +{ + return mUsePolygonStyle->isChecked(); +} + +void FancyPlotterSettings::setHorizontalScale( int scale ) +{ + mHorizontalScale->setValue( scale ); +} + +int FancyPlotterSettings::horizontalScale() const +{ + return mHorizontalScale->value(); +} + +void FancyPlotterSettings::setShowVerticalLines( bool value ) +{ + mShowVerticalLines->setChecked( value ); + mVerticalLinesDistance->setEnabled( value ); + mVerticalLinesScroll->setEnabled( value ); + mVerticalLinesColor->setEnabled( value ); +} + +bool FancyPlotterSettings::showVerticalLines() const +{ + return mShowVerticalLines->isChecked(); +} + +void FancyPlotterSettings::setVerticalLinesColor( const QColor &color ) +{ + mVerticalLinesColor->setColor( color ); +} + +QColor FancyPlotterSettings::verticalLinesColor() const +{ + return mVerticalLinesColor->color(); +} + +void FancyPlotterSettings::setVerticalLinesDistance( int distance ) +{ + mVerticalLinesDistance->setValue( distance ); +} + +int FancyPlotterSettings::verticalLinesDistance() const +{ + return mVerticalLinesDistance->value(); +} + +void FancyPlotterSettings::setVerticalLinesScroll( bool value ) +{ + mVerticalLinesScroll->setChecked( value ); +} + +bool FancyPlotterSettings::verticalLinesScroll() const +{ + return mVerticalLinesScroll->isChecked(); +} + +void FancyPlotterSettings::setShowHorizontalLines( bool value ) +{ + mShowHorizontalLines->setChecked( value ); + mHorizontalLinesCount->setEnabled( value ); + mHorizontalLinesColor->setEnabled( value ); + mShowLabels->setEnabled( value ); + +} + +bool FancyPlotterSettings::showHorizontalLines() const +{ + return mShowHorizontalLines->isChecked(); +} + +void FancyPlotterSettings::setHorizontalLinesColor( const QColor &color ) +{ + mHorizontalLinesColor->setColor( color ); +} + +QColor FancyPlotterSettings::horizontalLinesColor() const +{ + return mHorizontalLinesColor->color(); +} + +void FancyPlotterSettings::setHorizontalLinesCount( int count ) +{ + mHorizontalLinesCount->setValue( count ); +} + +int FancyPlotterSettings::horizontalLinesCount() const +{ + return mHorizontalLinesCount->value(); +} + +void FancyPlotterSettings::setShowLabels( bool value ) +{ + mShowLabels->setChecked( value ); +} + +bool FancyPlotterSettings::showLabels() const +{ + return mShowLabels->isChecked(); +} + +void FancyPlotterSettings::setShowTopBar( bool value ) +{ + mShowTopBar->setChecked( value ); +} + +bool FancyPlotterSettings::showTopBar() const +{ + return mShowTopBar->isChecked(); +} + +void FancyPlotterSettings::setFontSize( int size ) +{ + mFontSize->setValue( size ); +} + +int FancyPlotterSettings::fontSize() const +{ + return mFontSize->value(); +} + +void FancyPlotterSettings::setBackgroundColor( const QColor &color ) +{ + mBackgroundColor->setColor( color ); +} + +QColor FancyPlotterSettings::backgroundColor() const +{ + return mBackgroundColor->color(); +} +void FancyPlotterSettings::clearDeleted() +{ + mDeleted.clear(); +} +QValueList<int> FancyPlotterSettings::deleted() const +{ + return mDeleted; +} + +QValueList<int> FancyPlotterSettings::order() const +{ + QValueList<int> newOrder; + + QListViewItemIterator it( mSensorView ); + for ( ; it.current(); ++it ) { + newOrder.prepend(it.current()->text(0).toInt()); + } + return newOrder; +} + +void FancyPlotterSettings::resetOrder() +{ + int i = mSensorView->childCount()-1; + QListViewItemIterator it( mSensorView ); + for ( ; it.current(); ++it, --i) { + it.current()->setText(0, QString::number(i)); + } +} + +void FancyPlotterSettings::setSensors( const QValueList< QStringList > &list ) +{ + mSensorView->clear(); + + QValueList< QStringList >::ConstIterator it; + for ( it = list.begin(); it != list.end(); ++it ) { + QListViewItem* lvi = new QListViewItem( mSensorView, + (*it)[ 0 ], // id + (*it)[ 1 ], // host name + (*it)[ 2 ], // sensor name + (*it)[ 3 ], // unit + (*it)[ 4 ] ); // status + QPixmap pm( 12, 12 ); + pm.fill( QColor( (*it)[ 5 ] ) ); + lvi->setPixmap( 2, pm ); + mSensorView->insertItem( lvi ); + } +} + +QValueList< QStringList > FancyPlotterSettings::sensors() const +{ + QValueList< QStringList > list; + + QListViewItemIterator it( mSensorView ); + + for ( ; it.current(); ++it ) { + QStringList entry; + entry << it.current()->text( 0 ); + entry << it.current()->text( 1 ); + entry << it.current()->text( 2 ); + entry << it.current()->text( 3 ); + entry << it.current()->text( 4 ); + QRgb rgb = it.current()->pixmap( 2 )->convertToImage().pixel( 1, 1 ); + QColor color( qRed( rgb ), qGreen( rgb ), qBlue( rgb ) ); + entry << ( color.name() ); + + list.prepend( entry ); + } + + return list; +} + +void FancyPlotterSettings::editSensor() +{ + QListViewItem* lvi = mSensorView->currentItem(); + + if ( !lvi ) + return; + + QColor color = lvi->pixmap( 2 )->convertToImage().pixel( 1, 1 ); + int result = KColorDialog::getColor( color, parentWidget() ); + if ( result == KColorDialog::Accepted ) { + QPixmap newPm( 12, 12 ); + newPm.fill( color ); + lvi->setPixmap( 2, newPm ); + } +} + +void FancyPlotterSettings::removeSensor() +{ + QListViewItem* lvi = mSensorView->currentItem(); + + if ( lvi ) { + //Note down the id of the one we are deleting + int id = lvi->text(0).toInt(); + mDeleted.append(id); + + /* Before we delete the currently selected item, we determine a + * new item to be selected. That way we can ensure that multiple + * items can be deleted without forcing the user to select a new + * item between the deletes. If all items are deleted, the buttons + * are disabled again. */ + QListViewItem* newSelected = 0; + if ( lvi->itemBelow() ) { + lvi->itemBelow()->setSelected( true ); + newSelected = lvi->itemBelow(); + } else if ( lvi->itemAbove() ) { + lvi->itemAbove()->setSelected( true ); + newSelected = lvi->itemAbove(); + } else + selectionChanged( 0 ); + + delete lvi; + + QListViewItemIterator it( mSensorView ); + for ( ; it.current(); ++it ) { + if(it.current()->text(0).toInt() > id) + it.current()->setText(0, QString::number(it.current()->text(0).toInt() -1)); + } + + + if ( newSelected ) + mSensorView->ensureItemVisible( newSelected ); + } +} + +void FancyPlotterSettings::moveUpSensor() +{ + if ( mSensorView->currentItem() != 0 ) { + QListViewItem* item = mSensorView->currentItem()->itemAbove(); + if ( item ) { + if ( item->itemAbove() ) + { + mSensorView->currentItem()->moveItem( item->itemAbove() ); + } + else + { + item->moveItem( mSensorView->currentItem() ); + } + } + + selectionChanged( mSensorView->currentItem() ); + } +} + +void FancyPlotterSettings::moveDownSensor() +{ + if ( mSensorView->currentItem() != 0 ) { + if ( mSensorView->currentItem()->itemBelow() ) + mSensorView->currentItem()->moveItem( mSensorView->currentItem()->itemBelow() ); + + selectionChanged( mSensorView->currentItem() ); + } +} + +void FancyPlotterSettings::selectionChanged( QListViewItem *item ) +{ + bool state = ( item != 0 ); + + mEditButton->setEnabled( state ); + mRemoveButton->setEnabled( state ); + mMoveUpButton->setEnabled( state && item->itemAbove() ); + mMoveDownButton->setEnabled( state && item->itemBelow() ); +} + +#include "FancyPlotterSettings.moc" diff --git a/ksysguard/gui/SensorDisplayLib/FancyPlotterSettings.h b/ksysguard/gui/SensorDisplayLib/FancyPlotterSettings.h new file mode 100644 index 000000000..b813bee34 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/FancyPlotterSettings.h @@ -0,0 +1,143 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef FANCYPLOTTERSETTINGS_H +#define FANCYPLOTTERSETTINGS_H + +#include <kdialogbase.h> + +class KColorButton; +class KIntNumInput; +class KLineEdit; +class KListView; + +class QCheckBox; +class QListViewItem; +class QPushButton; +class QRadioButton; + +class FancyPlotterSettings : public KDialogBase +{ + Q_OBJECT + + public: + FancyPlotterSettings( QWidget* parent = 0, const char* name = 0 ); + ~FancyPlotterSettings(); + + void setTitle( const QString &title ); + QString title() const; + + void setUseAutoRange( bool value ); + bool useAutoRange() const; + + void setMinValue( double min ); + double minValue() const; + + void setMaxValue( double max ); + double maxValue() const; + + void setUsePolygonStyle( bool value ); + bool usePolygonStyle() const; + + void setHorizontalScale( int scale ); + int horizontalScale() const; + + void setShowVerticalLines( bool value ); + bool showVerticalLines() const; + + void setVerticalLinesColor( const QColor &color ); + QColor verticalLinesColor() const; + + void setVerticalLinesDistance( int distance ); + int verticalLinesDistance() const; + + void setVerticalLinesScroll( bool value ); + bool verticalLinesScroll() const; + + void setShowHorizontalLines( bool value ); + bool showHorizontalLines() const; + + void setHorizontalLinesColor( const QColor &color ); + QColor horizontalLinesColor() const; + + void setHorizontalLinesCount( int count ); + int horizontalLinesCount() const; + + void setShowLabels( bool value ); + bool showLabels() const; + + void setShowTopBar( bool value ); + bool showTopBar() const; + + void setFontSize( int size ); + int fontSize() const; + + void setBackgroundColor( const QColor &color ); + QColor backgroundColor() const; + + void setSensors( const QValueList< QStringList > &list ); + QValueList< QStringList > sensors() const; + QValueList<int> order() const; + QValueList<int> deleted() const; + void clearDeleted(); + void resetOrder(); + + private slots: + void editSensor(); + void removeSensor(); + void moveUpSensor(); + void moveDownSensor(); + void selectionChanged( QListViewItem* ); + + private: + + KColorButton *mVerticalLinesColor; + KColorButton *mHorizontalLinesColor; + KColorButton *mBackgroundColor; + KLineEdit *mMinValue; + KLineEdit *mMaxValue; + KLineEdit *mTitle; + KIntNumInput *mHorizontalScale; + KIntNumInput *mVerticalLinesDistance; + KIntNumInput *mHorizontalLinesCount; + KIntNumInput *mFontSize; + KListView *mSensorView; + + QCheckBox *mShowVerticalLines; + QCheckBox *mShowHorizontalLines; + QCheckBox *mVerticalLinesScroll; + QCheckBox *mUseAutoRange; + QCheckBox *mShowLabels; + QCheckBox *mShowTopBar; + QPushButton *mEditButton; + QPushButton *mRemoveButton; + QPushButton *mMoveUpButton; + QPushButton *mMoveDownButton; + QRadioButton *mUsePolygonStyle; + QRadioButton *mUseOriginalStyle; + + /** The numbers of the sensors to be delete.*/ + QValueList<int> mDeleted; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/ListView.cc b/ksysguard/gui/SensorDisplayLib/ListView.cc new file mode 100644 index 000000000..885daded6 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ListView.cc @@ -0,0 +1,371 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> + +#include <config.h> +#include <qdom.h> + +#include <kcolorbutton.h> +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> + +#include "ListView.h" +#include "ListView.moc" +#include "ListViewSettings.h" + +PrivateListViewItem::PrivateListViewItem(PrivateListView *parent) + : QListViewItem(parent) +{ + _parent = parent; +} + +int PrivateListViewItem::compare( QListViewItem *item, int col, bool ascending ) const +{ + int type = ((PrivateListView*)listView())->columnType( col ); + + if ( type == PrivateListView::Int ) { + int prev = (int)KGlobal::locale()->readNumber( key( col, ascending ) ); + int next = (int)KGlobal::locale()->readNumber( item->key( col, ascending ) ); + if ( prev < next ) + return -1; + else if ( prev == next ) + return 0; + else + return 1; + } else if ( type == PrivateListView::Float ) { + double prev = KGlobal::locale()->readNumber( key( col, ascending ) ); + double next = KGlobal::locale()->readNumber( item->key( col, ascending ) ); + if ( prev < next ) + return -1; + else + return 1; + } else if ( type == PrivateListView::Time ) { + int hourPrev, hourNext, minutesPrev, minutesNext; + sscanf( key( col, ascending ).latin1(), "%d:%d", &hourPrev, &minutesPrev ); + sscanf( item->key( col, ascending ).latin1(), "%d:%d", &hourNext, &minutesNext ); + int prev = hourPrev * 60 + minutesPrev; + int next = hourNext * 60 + minutesNext; + if ( prev < next ) + return -1; + else if ( prev == next ) + return 0; + else + return 1; + } else if ( type == PrivateListView::DiskStat ) { + QString prev = key( col, ascending ); + QString next = item->key( col, ascending ); + QString prevKey, nextKey; + + uint counter = prev.length(); + for ( uint i = 0; i < counter; ++i ) + if ( prev[ i ].isDigit() ) { + prevKey.sprintf( "%s%016d", prev.left( i ).latin1(), prev.mid( i ).toInt() ); + break; + } + + counter = next.length(); + for ( uint i = 0; i < counter; ++i ) + if ( next[ i ].isDigit() ) { + nextKey.sprintf( "%s%016d", next.left( i ).latin1(), next.mid( i ).toInt() ); + break; + } + + return prevKey.compare( nextKey ); + } else + return key( col, ascending ).localeAwareCompare( item->key( col, ascending ) ); +} + +PrivateListView::PrivateListView(QWidget *parent, const char *name) + : QListView(parent, name) +{ + QColorGroup cg = colorGroup(); + + cg.setColor(QColorGroup::Link, KSGRD::Style->firstForegroundColor()); + cg.setColor(QColorGroup::Text, KSGRD::Style->secondForegroundColor()); + cg.setColor(QColorGroup::Base, KSGRD::Style->backgroundColor()); + + setPalette(QPalette(cg, cg, cg)); +} + +void PrivateListView::update(const QString& answer) +{ + setUpdatesEnabled(false); + viewport()->setUpdatesEnabled(false); + + int vpos = verticalScrollBar()->value(); + int hpos = horizontalScrollBar()->value(); + + clear(); + + KSGRD::SensorTokenizer lines(answer, '\n'); + for (uint i = 0; i < lines.count(); i++) { + PrivateListViewItem *item = new PrivateListViewItem(this); + KSGRD::SensorTokenizer records(lines[i], '\t'); + for (uint j = 0; j < records.count(); j++) { + if ( mColumnTypes[ j ] == "f" ) + item->setText(j, KGlobal::locale()->formatNumber( records[j].toFloat() ) ); + else if ( mColumnTypes[ j ] == "D" ) + item->setText(j, KGlobal::locale()->formatNumber( records[j].toDouble(), 0 ) ); + else + item->setText(j, records[j]); + } + + insertItem(item); + } + + verticalScrollBar()->setValue(vpos); + horizontalScrollBar()->setValue(hpos); + + viewport()->setUpdatesEnabled(true); + setUpdatesEnabled(true); + + triggerUpdate(); +} + +int PrivateListView::columnType( uint pos ) const +{ + if ( pos >= mColumnTypes.count() ) + return 0; + + if ( mColumnTypes[ pos ] == "d" || mColumnTypes[ pos ] == "D" ) + return Int; + else if ( mColumnTypes[ pos ] == "f" || mColumnTypes[ pos ] == "F" ) + return Float; + else if ( mColumnTypes[ pos ] == "t" ) + return Time; + else if ( mColumnTypes[ pos ] == "M" ) + return DiskStat; + else + return Text; +} + +void PrivateListView::removeColumns(void) +{ + for (int i = columns() - 1; i >= 0; --i) + removeColumn(i); +} + +void PrivateListView::addColumn(const QString& label, const QString& type) +{ + QListView::addColumn( label ); + int col = columns() - 1; + + if (type == "s" || type == "S") + setColumnAlignment(col, AlignLeft); + else if (type == "d" || type == "D") + setColumnAlignment(col, AlignRight); + else if (type == "t") + setColumnAlignment(col, AlignRight); + else if (type == "f") + setColumnAlignment(col, AlignRight); + else if (type == "M") + setColumnAlignment(col, AlignLeft); + else + { + kdDebug(1215) << "Unknown type " << type << " of column " << label + << " in ListView!" << endl; + return; + } + + mColumnTypes.append( type ); + + /* Just use some sensible default values as initial setting. */ + QFontMetrics fm = fontMetrics(); + setColumnWidth(col, fm.width(label) + 10); +} + +ListView::ListView(QWidget* parent, const char* name, const QString& title, int, int) + : KSGRD::SensorDisplay(parent, name, title) +{ + setBackgroundColor(KSGRD::Style->backgroundColor()); + + monitor = new PrivateListView( frame() ); + Q_CHECK_PTR(monitor); + monitor->setSelectionMode(QListView::NoSelection); + monitor->setItemMargin(2); + + setMinimumSize(50, 25); + + setPlotterWidget(monitor); + + setModified(false); +} + +bool +ListView::addSensor(const QString& hostName, const QString& sensorName, const QString& sensorType, const QString& title) +{ + if (sensorType != "listview") + return (false); + + registerSensor(new KSGRD::SensorProperties(hostName, sensorName, sensorType, title)); + + setTitle(title); + + /* To differentiate between answers from value requests and info + * requests we use 100 for info requests. */ + sendRequest(hostName, sensorName + "?", 100); + sendRequest(hostName, sensorName, 19); + setModified(true); + return (true); +} + +void +ListView::updateList() +{ + sendRequest(sensors().at(0)->hostName(), sensors().at(0)->name(), 19); +} + +void +ListView::answerReceived(int id, const QString& answer) +{ + /* We received something, so the sensor is probably ok. */ + sensorError(id, false); + + switch (id) + { + case 100: { + /* We have received the answer to a '?' command that contains + * the information about the table headers. */ + KSGRD::SensorTokenizer lines(answer, '\n'); + if (lines.count() != 2) + { + kdDebug(1215) << "wrong number of lines" << endl; + return; + } + KSGRD::SensorTokenizer headers(lines[0], '\t'); + KSGRD::SensorTokenizer colTypes(lines[1], '\t'); + + /* remove all columns from list */ + monitor->removeColumns(); + + /* add the new columns */ + for (unsigned int i = 0; i < headers.count(); i++) + /* TODO: Implement translation support for header texts */ + monitor->addColumn(headers[i], colTypes[i]); + break; + } + case 19: { + monitor->update(answer); + break; + } + } +} + +void +ListView::resizeEvent(QResizeEvent*) +{ + frame()->setGeometry(0, 0, width(), height()); + monitor->setGeometry(10, 20, width() - 20, height() - 30); +} + +bool +ListView::restoreSettings(QDomElement& element) +{ + addSensor(element.attribute("hostName"), element.attribute("sensorName"), (element.attribute("sensorType").isEmpty() ? "listview" : element.attribute("sensorType")), element.attribute("title")); + + QColorGroup colorGroup = monitor->colorGroup(); + colorGroup.setColor(QColorGroup::Link, restoreColor(element, "gridColor", KSGRD::Style->firstForegroundColor())); + colorGroup.setColor(QColorGroup::Text, restoreColor(element, "textColor", KSGRD::Style->secondForegroundColor())); + colorGroup.setColor(QColorGroup::Base, restoreColor(element, "backgroundColor", KSGRD::Style->backgroundColor())); + + monitor->setPalette(QPalette(colorGroup, colorGroup, colorGroup)); + + SensorDisplay::restoreSettings(element); + + setModified(false); + + return (true); +} + +bool +ListView::saveSettings(QDomDocument& doc, QDomElement& element, bool save) +{ + element.setAttribute("hostName", sensors().at(0)->hostName()); + element.setAttribute("sensorName", sensors().at(0)->name()); + element.setAttribute("sensorType", sensors().at(0)->type()); + + QColorGroup colorGroup = monitor->colorGroup(); + saveColor(element, "gridColor", colorGroup.color(QColorGroup::Link)); + saveColor(element, "textColor", colorGroup.color(QColorGroup::Text)); + saveColor(element, "backgroundColor", colorGroup.color(QColorGroup::Base)); + + SensorDisplay::saveSettings(doc, element); + + if (save) + setModified(false); + + return (true); +} + +void +ListView::configureSettings() +{ + lvs = new ListViewSettings(this, "ListViewSettings"); + Q_CHECK_PTR(lvs); + connect(lvs, SIGNAL(applyClicked()), SLOT(applySettings())); + + QColorGroup colorGroup = monitor->colorGroup(); + lvs->setGridColor(colorGroup.color(QColorGroup::Link)); + lvs->setTextColor(colorGroup.color(QColorGroup::Text)); + lvs->setBackgroundColor(colorGroup.color(QColorGroup::Base)); + lvs->setTitle(title()); + + if (lvs->exec()) + applySettings(); + + delete lvs; + lvs = 0; +} + +void +ListView::applySettings() +{ + QColorGroup colorGroup = monitor->colorGroup(); + colorGroup.setColor(QColorGroup::Link, lvs->gridColor()); + colorGroup.setColor(QColorGroup::Text, lvs->textColor()); + colorGroup.setColor(QColorGroup::Base, lvs->backgroundColor()); + monitor->setPalette(QPalette(colorGroup, colorGroup, colorGroup)); + + setTitle(lvs->title()); + + setModified(true); +} + +void +ListView::applyStyle() +{ + QColorGroup colorGroup = monitor->colorGroup(); + colorGroup.setColor(QColorGroup::Link, KSGRD::Style->firstForegroundColor()); + colorGroup.setColor(QColorGroup::Text, KSGRD::Style->secondForegroundColor()); + colorGroup.setColor(QColorGroup::Base, KSGRD::Style->backgroundColor()); + monitor->setPalette(QPalette(colorGroup, colorGroup, colorGroup)); + + setModified(true); +} diff --git a/ksysguard/gui/SensorDisplayLib/ListView.h b/ksysguard/gui/SensorDisplayLib/ListView.h new file mode 100644 index 000000000..4b96329c0 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ListView.h @@ -0,0 +1,112 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef _ListView_h_ +#define _ListView_h_ + +#include <qlistview.h> +#include <qpainter.h> + +#include <SensorDisplay.h> + +typedef const char* (*KeyFunc)(const char*); + +class QLabel; +class QBoxGroup; +class ListViewSettings; + +class PrivateListView : public QListView +{ + Q_OBJECT +public: + enum ColumnType { Text, Int, Float, Time, DiskStat }; + + PrivateListView(QWidget *parent = 0, const char *name = 0); + + void addColumn(const QString& label, const QString& type); + void removeColumns(void); + void update(const QString& answer); + int columnType( uint pos ) const; + +private: + QStringList mColumnTypes; +}; + +class PrivateListViewItem : public QListViewItem +{ +public: + PrivateListViewItem(PrivateListView *parent = 0); + + void paintCell(QPainter *p, const QColorGroup &, int column, int width, int alignment) { + QColorGroup cgroup = _parent->colorGroup(); + QListViewItem::paintCell(p, cgroup, column, width, alignment); + p->setPen(cgroup.color(QColorGroup::Link)); + p->drawLine(0, height() - 1, width - 1, height() - 1); + } + + void paintFocus(QPainter *, const QColorGroup, const QRect) {} + + virtual int compare( QListViewItem*, int column, bool ascending ) const; + +private: + QWidget *_parent; +}; + +class ListView : public KSGRD::SensorDisplay +{ + Q_OBJECT +public: + ListView(QWidget* parent = 0, const char* name = 0, + const QString& = QString::null, int min = 0, int max = 0); + ~ListView() {} + + bool addSensor(const QString& hostName, const QString& sensorName, const QString& sensorType, const QString& sensorDescr); + void answerReceived(int id, const QString& answer); + void resizeEvent(QResizeEvent*); + void updateList(); + + bool restoreSettings(QDomElement& element); + bool saveSettings(QDomDocument& doc, QDomElement& element, bool save = true); + + virtual bool hasSettingsDialog() const + { + return (true); + } + + virtual void timerEvent(QTimerEvent*) + { + updateList(); + } + + void configureSettings(); + +public slots: + void applySettings(); + void applyStyle(); + +private: + PrivateListView* monitor; + ListViewSettings* lvs; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/ListViewSettings.cc b/ksysguard/gui/SensorDisplayLib/ListViewSettings.cc new file mode 100644 index 000000000..15822206e --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ListViewSettings.cc @@ -0,0 +1,77 @@ +/* This file is part of the KDE project + Copyright ( C ) 2003 Nadeem Hasan <nhasan@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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "ListViewSettings.h" +#include "ListViewSettingsWidget.h" + +#include <klocale.h> + +ListViewSettings::ListViewSettings( QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n( "List View Settings" ), + Ok|Apply|Cancel, Ok, true ) +{ + m_settingsWidget = new ListViewSettingsWidget( this, "m_settingsWidget" ); + setMainWidget( m_settingsWidget ); +} + +QString ListViewSettings::title() const +{ + return m_settingsWidget->title(); +} + +QColor ListViewSettings::textColor() const +{ + return m_settingsWidget->textColor(); +} + +QColor ListViewSettings::backgroundColor() const +{ + return m_settingsWidget->backgroundColor(); +} + +QColor ListViewSettings::gridColor() const +{ + return m_settingsWidget->gridColor(); +} + +void ListViewSettings::setTitle( const QString &title ) +{ + m_settingsWidget->setTitle( title ); +} + +void ListViewSettings::setBackgroundColor( const QColor &c ) +{ + m_settingsWidget->setBackgroundColor( c ); +} + +void ListViewSettings::setTextColor( const QColor &c ) +{ + m_settingsWidget->setTextColor( c ); +} + +void ListViewSettings::setGridColor( const QColor &c ) +{ + m_settingsWidget->setGridColor( c ); +} + +#include "ListViewSettings.moc" + +/* vim: et sw=2 ts=2 +*/ + diff --git a/ksysguard/gui/SensorDisplayLib/ListViewSettings.h b/ksysguard/gui/SensorDisplayLib/ListViewSettings.h new file mode 100644 index 000000000..9a9790791 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ListViewSettings.h @@ -0,0 +1,57 @@ +/* This file is part of the KDE project + Copyright ( C ) 2003 Nadeem Hasan <nhasan@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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#ifndef LISTVIEWSETTINGS_H +#define LISTVIEWSETTINGS_H + +#include <kdialogbase.h> + +#include <qstring.h> +#include <qcolor.h> + +class ListViewSettingsWidget; + +class ListViewSettings : public KDialogBase +{ + Q_OBJECT + + public: + + ListViewSettings( QWidget *parent=0, const char *name=0 ); + + QString title() const; + QColor textColor() const; + QColor backgroundColor() const; + QColor gridColor() const; + + void setTitle( const QString & ); + void setTextColor( const QColor & ); + void setBackgroundColor( const QColor & ); + void setGridColor( const QColor & ); + + private: + + ListViewSettingsWidget *m_settingsWidget; +}; + +#endif // LISTVIEWSETTINGS_H + +/* vim: et sw=2 ts=2 +*/ diff --git a/ksysguard/gui/SensorDisplayLib/ListViewSettingsWidget.ui b/ksysguard/gui/SensorDisplayLib/ListViewSettingsWidget.ui new file mode 100644 index 000000000..f61f30dd7 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ListViewSettingsWidget.ui @@ -0,0 +1,178 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>ListViewSettingsWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>ListViewSettingsWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>399</width> + <height>202</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>titleFrame</cstring> + </property> + <property name="title"> + <string>Title</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_title</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>colorFrame</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>Box</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="title"> + <string>Colors</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter|AlignLeft</set> + </property> + <property name="vAlign" stdset="0"> + </property> + <property name="wordwrap" stdset="0"> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Text color:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Grid color:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Background color:</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget" row="0" column="1"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_textColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>0</red> + <green>255</green> + <blue>0</blue> + </color> + </property> + </widget> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_gridColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>0</red> + <green>0</green> + <blue>0</blue> + </color> + </property> + </widget> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_backgroundColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </property> + </widget> + </vbox> + </widget> + </grid> + </widget> + </vbox> +</widget> +<includes> + <include location="global" impldecl="in implementation">kdialog.h</include> + <include location="local" impldecl="in implementation">ListViewSettingsWidget.ui.h</include> +</includes> +<functions> + <function specifier="non virtual" returnType="QString">title()</function> + <function specifier="non virtual" returnType="QColor">gridColor()</function> + <function specifier="non virtual" returnType="QColor">backgroundColor()</function> + <function specifier="non virtual" returnType="QColor">textColor()</function> + <function specifier="non virtual">setTitle( const QString & t )</function> + <function specifier="non virtual">setBackgroundColor( const QColor & c )</function> + <function specifier="non virtual">setTextColor( const QColor & c )</function> + <function specifier="non virtual">setGridColor( const QColor & c )</function> +</functions> +<layoutdefaults spacing="6" margin="11"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +</UI> diff --git a/ksysguard/gui/SensorDisplayLib/ListViewSettingsWidget.ui.h b/ksysguard/gui/SensorDisplayLib/ListViewSettingsWidget.ui.h new file mode 100644 index 000000000..14ff5990d --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ListViewSettingsWidget.ui.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + + +QString ListViewSettingsWidget::title() +{ + return m_title->text(); +} + + +QColor ListViewSettingsWidget::gridColor() +{ + return m_gridColor->color(); +} + + +QColor ListViewSettingsWidget::backgroundColor() +{ + return m_backgroundColor->color(); +} + + +QColor ListViewSettingsWidget::textColor() +{ + return m_textColor->color(); +} + + +void ListViewSettingsWidget::setTitle( const QString &t ) +{ + m_title->setText(t); +} + + +void ListViewSettingsWidget::setBackgroundColor( const QColor &c ) +{ + m_backgroundColor->setColor(c); +} + + +void ListViewSettingsWidget::setTextColor( const QColor &c ) +{ + m_textColor->setColor(c); +} + + +void ListViewSettingsWidget::setGridColor( const QColor &c ) +{ + m_gridColor->setColor(c); +} diff --git a/ksysguard/gui/SensorDisplayLib/LogFile.cc b/ksysguard/gui/SensorDisplayLib/LogFile.cc new file mode 100644 index 000000000..9db4c7116 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/LogFile.cc @@ -0,0 +1,285 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdio.h> +#include <sys/types.h> + +#include <qpushbutton.h> +#include <qregexp.h> + +#include <qfile.h> +#include <qlistbox.h> + +#include <kfontdialog.h> +#include <kdebug.h> +#include <klocale.h> +#include <kcolorbutton.h> + +#include <ksgrd/StyleEngine.h> + +#include "LogFile.moc" + +LogFile::LogFile(QWidget *parent, const char *name, const QString& title) + : KSGRD::SensorDisplay(parent, name, title) +{ + monitor = new QListBox(this); + Q_CHECK_PTR(monitor); + + setMinimumSize(50, 25); + + setPlotterWidget(monitor); + + setModified(false); +} + +LogFile::~LogFile(void) +{ + sendRequest(sensors().at(0)->hostName(), QString("logfile_unregister %1" ).arg(logFileID), 43); +} + +bool +LogFile::addSensor(const QString& hostName, const QString& sensorName, const QString& sensorType, const QString& title) +{ + if (sensorType != "logfile") + return (false); + + registerSensor(new KSGRD::SensorProperties(hostName, sensorName, sensorType, title)); + + QString sensorID = sensorName.right(sensorName.length() - (sensorName.findRev("/") + 1)); + + sendRequest(sensors().at(0)->hostName(), QString("logfile_register %1" ).arg(sensorID), 42); + + if (title.isEmpty()) + setTitle(sensors().at(0)->hostName() + ":" + sensorID); + else + setTitle(title); + + setModified(true); + + return (true); +} + + +void LogFile::configureSettings(void) +{ + QColorGroup cgroup = monitor->colorGroup(); + + lfs = new LogFileSettings(this); + Q_CHECK_PTR(lfs); + + lfs->fgColor->setColor(cgroup.text()); + lfs->fgColor->setText(i18n("Foreground color:")); + lfs->bgColor->setColor(cgroup.base()); + lfs->bgColor->setText(i18n("Background color:")); + lfs->fontButton->setFont(monitor->font()); + lfs->ruleList->insertStringList(filterRules); + lfs->title->setText(title()); + + connect(lfs->okButton, SIGNAL(clicked()), lfs, SLOT(accept())); + connect(lfs->applyButton, SIGNAL(clicked()), this, SLOT(applySettings())); + connect(lfs->cancelButton, SIGNAL(clicked()), lfs, SLOT(reject())); + + connect(lfs->fontButton, SIGNAL(clicked()), this, SLOT(settingsFontSelection())); + connect(lfs->addButton, SIGNAL(clicked()), this, SLOT(settingsAddRule())); + connect(lfs->deleteButton, SIGNAL(clicked()), this, SLOT(settingsDeleteRule())); + connect(lfs->changeButton, SIGNAL(clicked()), this, SLOT(settingsChangeRule())); + connect(lfs->ruleList, SIGNAL(selected(int)), this, SLOT(settingsRuleListSelected(int))); + connect(lfs->ruleText, SIGNAL(returnPressed()), this, SLOT(settingsAddRule())); + + if (lfs->exec()) { + applySettings(); + } + + delete lfs; + lfs = 0; +} + +void LogFile::settingsFontSelection() +{ + QFont tmpFont = lfs->fontButton->font(); + + if (KFontDialog::getFont(tmpFont) == KFontDialog::Accepted) { + lfs->fontButton->setFont(tmpFont); + } +} + +void LogFile::settingsAddRule() +{ + if (!lfs->ruleText->text().isEmpty()) { + lfs->ruleList->insertItem(lfs->ruleText->text(), -1); + lfs->ruleText->setText(""); + } +} + +void LogFile::settingsDeleteRule() +{ + lfs->ruleList->removeItem(lfs->ruleList->currentItem()); + lfs->ruleText->setText(""); +} + +void LogFile::settingsChangeRule() +{ + lfs->ruleList->changeItem(lfs->ruleText->text(), lfs->ruleList->currentItem()); + lfs->ruleText->setText(""); +} + +void LogFile::settingsRuleListSelected(int index) +{ + lfs->ruleText->setText(lfs->ruleList->text(index)); +} + +void LogFile::applySettings(void) +{ + QColorGroup cgroup = monitor->colorGroup(); + + cgroup.setColor(QColorGroup::Text, lfs->fgColor->color()); + cgroup.setColor(QColorGroup::Base, lfs->bgColor->color()); + monitor->setPalette(QPalette(cgroup, cgroup, cgroup)); + monitor->setFont(lfs->fontButton->font()); + + filterRules.clear(); + for (uint i = 0; i < lfs->ruleList->count(); i++) + filterRules.append(lfs->ruleList->text(i)); + + setTitle(lfs->title->text()); + + setModified(true); +} + +void +LogFile::applyStyle() +{ + QColorGroup cgroup = monitor->colorGroup(); + + cgroup.setColor(QColorGroup::Text, KSGRD::Style->firstForegroundColor()); + cgroup.setColor(QColorGroup::Base, KSGRD::Style->backgroundColor()); + monitor->setPalette(QPalette(cgroup, cgroup, cgroup)); + + setModified(true); +} + +bool +LogFile::restoreSettings(QDomElement& element) +{ + QFont font; + QColorGroup cgroup = monitor->colorGroup(); + + cgroup.setColor(QColorGroup::Text, restoreColor(element, "textColor", Qt::green)); + cgroup.setColor(QColorGroup::Base, restoreColor(element, "backgroundColor", Qt::black)); + monitor->setPalette(QPalette(cgroup, cgroup, cgroup)); + + addSensor(element.attribute("hostName"), element.attribute("sensorName"), (element.attribute("sensorType").isEmpty() ? "logfile" : element.attribute("sensorType")), element.attribute("title")); + + font.fromString( element.attribute( "font" ) ); + monitor->setFont(font); + + QDomNodeList dnList = element.elementsByTagName("filter"); + for (uint i = 0; i < dnList.count(); i++) { + QDomElement element = dnList.item(i).toElement(); + filterRules.append(element.attribute("rule")); + } + + SensorDisplay::restoreSettings(element); + + setModified(false); + + return true; +} + +bool +LogFile::saveSettings(QDomDocument& doc, QDomElement& element, bool save) +{ + element.setAttribute("hostName", sensors().at(0)->hostName()); + element.setAttribute("sensorName", sensors().at(0)->name()); + element.setAttribute("sensorType", sensors().at(0)->type()); + + element.setAttribute("font", monitor->font().toString()); + + saveColor(element, "textColor", monitor->colorGroup().text()); + saveColor(element, "backgroundColor", monitor->colorGroup().base()); + + for (QStringList::Iterator it = filterRules.begin(); + it != filterRules.end(); it++) + { + QDomElement filter = doc.createElement("filter"); + filter.setAttribute("rule", (*it)); + element.appendChild(filter); + } + + SensorDisplay::saveSettings(doc, element); + + if (save) + setModified(false); + + return true; +} + +void +LogFile::updateMonitor() +{ + sendRequest(sensors().at(0)->hostName(), + QString("%1 %2" ).arg(sensors().at(0)->name()).arg(logFileID), 19); +} + +void +LogFile::answerReceived(int id, const QString& answer) +{ + /* We received something, so the sensor is probably ok. */ + sensorError(id, false); + + switch (id) + { + case 19: { + KSGRD::SensorTokenizer lines(answer, '\n'); + + for (uint i = 0; i < lines.count(); i++) { + if (monitor->count() == MAXLINES) + monitor->removeItem(0); + + monitor->insertItem(lines[i], -1); + + for (QStringList::Iterator it = filterRules.begin(); it != filterRules.end(); it++) { + QRegExp *expr = new QRegExp((*it).latin1()); + if (expr->search(lines[i].latin1()) != -1) { + KNotifyClient::event(winId(), "pattern_match", QString("rule '%1' matched").arg((*it).latin1())); + } + delete expr; + } + } + + monitor->setCurrentItem( monitor->count() - 1 ); + monitor->ensureCurrentVisible(); + + break; + } + + case 42: { + logFileID = answer.toULong(); + break; + } + } +} + +void +LogFile::resizeEvent(QResizeEvent*) +{ + frame()->setGeometry(0, 0, this->width(), this->height()); + monitor->setGeometry(10, 20, this->width() - 20, this->height() - 30); +} diff --git a/ksysguard/gui/SensorDisplayLib/LogFile.h b/ksysguard/gui/SensorDisplayLib/LogFile.h new file mode 100644 index 000000000..9428f934d --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/LogFile.h @@ -0,0 +1,85 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 _LogFile_h +#define _LogFile_h + +#define MAXLINES 500 + +class QFile; +class QListBox; + +#include <qdom.h> +#include <qpopupmenu.h> +#include <qstring.h> +#include <qstringlist.h> + +#include <SensorDisplay.h> + +#include "LogFileSettings.h" + +class LogFile : public KSGRD::SensorDisplay +{ + Q_OBJECT +public: + LogFile(QWidget *parent = 0, const char *name = 0, const QString& title = 0); + ~LogFile(void); + + bool addSensor(const QString& hostName, const QString& sensorName, + const QString& sensorType, const QString& sensorDescr); + void answerReceived(int id, const QString& answer); + void resizeEvent(QResizeEvent*); + + bool restoreSettings(QDomElement& element); + bool saveSettings(QDomDocument& doc, QDomElement& element, bool save = true); + + void updateMonitor(void); + + void configureSettings(void); + + virtual void timerEvent(QTimerEvent*) + { + updateMonitor(); + } + + virtual bool hasSettingsDialog() const + { + return (true); + } + +public slots: + void applySettings(); + void applyStyle(); + + void settingsFontSelection(); + void settingsAddRule(); + void settingsDeleteRule(); + void settingsChangeRule(); + void settingsRuleListSelected(int index); + +private: + LogFileSettings* lfs; + QListBox* monitor; + QStringList filterRules; + + unsigned long logFileID; +}; + +#endif // _LogFile_h diff --git a/ksysguard/gui/SensorDisplayLib/LogFileSettings.ui b/ksysguard/gui/SensorDisplayLib/LogFileSettings.ui new file mode 100644 index 000000000..b5dcff0ee --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/LogFileSettings.ui @@ -0,0 +1,345 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>LogFileSettings</class> +<author>Tobias Koenig <tokoe@kde.org></author> +<widget class="QDialog"> + <property name="name"> + <cstring>LogFileSettings</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>438</width> + <height>320</height> + </rect> + </property> + <property name="caption"> + <string>Log File Settings</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QTabWidget"> + <property name="name"> + <cstring>TabWidget</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Text</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>GroupBox8</cstring> + </property> + <property name="title"> + <string>Title</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>title</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>styleGroup</cstring> + </property> + <property name="title"> + <string>Colors</string> + </property> + <property name="exclusive"> + <bool>true</bool> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Foreground color:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Background color:</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KColorButton"> + <property name="name"> + <cstring>fgColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="KColorButton"> + <property name="name"> + <cstring>bgColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + </vbox> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer8</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>GroupBox11</cstring> + </property> + <property name="title"> + <string>Font</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>Spacer14</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>fontButton</cstring> + </property> + <property name="text"> + <string>Select Font...</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Filter</string> + </attribute> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout7</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>ruleText</cstring> + </property> + </widget> + <widget class="QListBox"> + <property name="name"> + <cstring>ruleList</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout9</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>addButton</cstring> + </property> + <property name="text"> + <string>&Add</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>deleteButton</cstring> + </property> + <property name="text"> + <string>&Delete</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>changeButton</cstring> + </property> + <property name="text"> + <string>&Change</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer7_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </hbox> + </widget> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>okButton</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>applyButton</cstring> + </property> + <property name="text"> + <string>&Apply</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>cancelButton</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<tabstops> + <tabstop>okButton</tabstop> + <tabstop>applyButton</tabstop> + <tabstop>cancelButton</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in implementation">kdialog.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +</UI> diff --git a/ksysguard/gui/SensorDisplayLib/Makefile.am b/ksysguard/gui/SensorDisplayLib/Makefile.am new file mode 100644 index 000000000..a1327a4ac --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/Makefile.am @@ -0,0 +1,39 @@ + +# set the include path for X, qt and KDE +INCLUDES= -I$(srcdir)/.. -I$(srcdir)/../ksgrd -I../ksgrd $(all_includes) + +noinst_LTLIBRARIES = libsensordisplays.la + +libsensordisplays_la_LDFLAGS = $(all_libraries) -no-undefined +libsensordisplays_la_LIBADD = ../ksgrd/libksgrd.la $(LIB_KIO) + +# Which sources should be compiled for the sensor display lib. +libsensordisplays_la_SOURCES = \ + SensorDisplay.cc \ + BarGraph.cc \ + DancingBars.cc \ + DancingBarsSettings.cc \ + DummyDisplay.cc \ + FancyPlotter.cc \ + FancyPlotterSettings.cc \ + ListView.cc \ + LogFile.cc \ + MultiMeter.cc \ + MultiMeterSettings.cc \ + ProcessController.cc \ + ProcessList.cc \ + ReniceDlg.cc \ + SensorLogger.cc \ + SensorLoggerDlg.cc \ + SensorLoggerSettings.cc \ + ListViewSettings.cc \ + SignalPlotter.cc \ + ListViewSettingsWidget.ui \ + LogFileSettings.ui \ + MultiMeterSettingsWidget.ui \ + SensorLoggerDlgWidget.ui \ + SensorLoggerSettingsWidget.ui + +# just to make sure, automake makes them +METASOURCES = AUTO + diff --git a/ksysguard/gui/SensorDisplayLib/MultiMeter.cc b/ksysguard/gui/SensorDisplayLib/MultiMeter.cc new file mode 100644 index 000000000..14e805b9d --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/MultiMeter.cc @@ -0,0 +1,258 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000, 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <math.h> +#include <stdlib.h> + +#include <qdom.h> +#include <qlcdnumber.h> +#include <qtooltip.h> + +#include <kdebug.h> + +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> + +#include "MultiMeter.moc" +#include "MultiMeterSettings.h" + +MultiMeter::MultiMeter(QWidget* parent, const char* name, + const QString& title, double, double, bool nf, bool isApplet) + : KSGRD::SensorDisplay(parent, name, title, nf, isApplet) +{ + setShowUnit( true ); + lowerLimit = upperLimit = 0; + lowerLimitActive = upperLimitActive = false; + + normalDigitColor = KSGRD::Style->firstForegroundColor(); + alarmDigitColor = KSGRD::Style->alarmColor(); + if (noFrame()) + lcd = new QLCDNumber(this, "meterLCD"); + else + lcd = new QLCDNumber(frame(), "meterLCD"); + Q_CHECK_PTR(lcd); + lcd->setSegmentStyle(QLCDNumber::Filled); + setDigitColor(KSGRD::Style->backgroundColor()); + lcd->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, + QSizePolicy::Expanding, false)); + + setBackgroundColor(KSGRD::Style->backgroundColor()); + /* All RMB clicks to the lcd widget will be handled by + * SensorDisplay::eventFilter. */ + lcd->installEventFilter(this); + + setPlotterWidget(lcd); + + setMinimumSize(5, 5); + setModified(false); +} + +bool +MultiMeter::addSensor(const QString& hostName, const QString& sensorName, + const QString& sensorType, const QString& title) +{ + if (sensorType != "integer" && sensorType != "float") + return (false); + + registerSensor(new KSGRD::SensorProperties(hostName, sensorName, sensorType, title)); + + /* To differentiate between answers from value requests and info + * requests we use 100 for info requests. */ + sendRequest(hostName, sensorName + "?", 100); + + QToolTip::remove(lcd); + QToolTip::add(lcd, QString("%1:%2").arg(hostName).arg(sensorName)); + + setModified(true); + return (true); +} + +void +MultiMeter::answerReceived(int id, const QString& answer) +{ + /* We received something, so the sensor is probably ok. */ + sensorError(id, false); + + if (id == 100) + { + KSGRD::SensorIntegerInfo info(answer); + setUnit(KSGRD::SensorMgr->translateUnit(info.unit())); + } + else + { + double val = answer.toDouble(); + int digits = (int) log10(val) + 1; + + if (noFrame()) + if (digits > 4) + lcd->setNumDigits(4); + else + lcd->setNumDigits(digits); + else + { + if (digits > 5) + lcd->setNumDigits(digits); + else + lcd->setNumDigits(5); + } + + lcd->display(val); + if (lowerLimitActive && val < lowerLimit) + { + setDigitColor(alarmDigitColor); + } + else if (upperLimitActive && val > upperLimit) + { + setDigitColor(alarmDigitColor); + } + else + setDigitColor(normalDigitColor); + } +} + +void +MultiMeter::resizeEvent(QResizeEvent*) +{ + if (noFrame()) + lcd->setGeometry(0, 0, width(), height()); + else + frame()->setGeometry(0, 0, width(), height()); +} + +bool +MultiMeter::restoreSettings(QDomElement& element) +{ + lowerLimitActive = element.attribute("lowerLimitActive").toInt(); + lowerLimit = element.attribute("lowerLimit").toLong(); + upperLimitActive = element.attribute("upperLimitActive").toInt(); + upperLimit = element.attribute("upperLimit").toLong(); + + normalDigitColor = restoreColor(element, "normalDigitColor", + KSGRD::Style->firstForegroundColor()); + alarmDigitColor = restoreColor(element, "alarmDigitColor", + KSGRD::Style->alarmColor()); + setBackgroundColor(restoreColor(element, "backgroundColor", + KSGRD::Style->backgroundColor())); + + addSensor(element.attribute("hostName"), element.attribute("sensorName"), (element.attribute("sensorType").isEmpty() ? "integer" : element.attribute("sensorType")), ""); + + SensorDisplay::restoreSettings(element); + + setModified(false); + + return (true); +} + +bool +MultiMeter::saveSettings(QDomDocument& doc, QDomElement& element, bool save) +{ + element.setAttribute("hostName", sensors().at(0)->hostName()); + element.setAttribute("sensorName", sensors().at(0)->name()); + element.setAttribute("sensorType", sensors().at(0)->type()); + element.setAttribute("showUnit", showUnit()); + element.setAttribute("lowerLimitActive", (int) lowerLimitActive); + element.setAttribute("lowerLimit", (int) lowerLimit); + element.setAttribute("upperLimitActive", (int) upperLimitActive); + element.setAttribute("upperLimit", (int) upperLimit); + + saveColor(element, "normalDigitColor", normalDigitColor); + saveColor(element, "alarmDigitColor", alarmDigitColor); + saveColor(element, "backgroundColor", lcd->backgroundColor()); + + SensorDisplay::saveSettings(doc, element); + + if (save) + setModified(false); + + return (true); +} + +void +MultiMeter::configureSettings() +{ + mms = new MultiMeterSettings(this, "MultiMeterSettings"); + Q_CHECK_PTR(mms); + mms->setTitle(title()); + mms->setShowUnit(showUnit()); + mms->setLowerLimitActive(lowerLimitActive); + mms->setLowerLimit(lowerLimit); + mms->setUpperLimitActive(upperLimitActive); + mms->setUpperLimit(upperLimit); + mms->setNormalDigitColor(normalDigitColor); + mms->setAlarmDigitColor(alarmDigitColor); + mms->setMeterBackgroundColor(lcd->backgroundColor()); + + connect(mms, SIGNAL(applyClicked()), SLOT(applySettings())); + + if (mms->exec()) + applySettings(); + + delete mms; + mms = 0; +} + +void +MultiMeter::applySettings() +{ + setShowUnit( mms->showUnit() ); + setTitle(mms->title()); + lowerLimitActive = mms->lowerLimitActive(); + lowerLimit = mms->lowerLimit(); + upperLimitActive = mms->upperLimitActive(); + upperLimit = mms->upperLimit(); + + normalDigitColor = mms->normalDigitColor(); + alarmDigitColor = mms->alarmDigitColor(); + setBackgroundColor(mms->meterBackgroundColor()); + + repaint(); + setModified(true); +} + +void +MultiMeter::applyStyle() +{ + normalDigitColor = KSGRD::Style->firstForegroundColor(); + setBackgroundColor(KSGRD::Style->backgroundColor()); + repaint(); + setModified(true); +} + +void +MultiMeter::setDigitColor(const QColor& col) +{ + QPalette p = lcd->palette(); + p.setColor(QColorGroup::Foreground, col); + lcd->setPalette(p); +} + +void +MultiMeter::setBackgroundColor(const QColor& col) +{ + lcd->setBackgroundColor(col); + + QPalette p = lcd->palette(); + p.setColor(QColorGroup::Light, col); + p.setColor(QColorGroup::Dark, col); + lcd->setPalette(p); +} diff --git a/ksysguard/gui/SensorDisplayLib/MultiMeter.h b/ksysguard/gui/SensorDisplayLib/MultiMeter.h new file mode 100644 index 000000000..58d2477c1 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/MultiMeter.h @@ -0,0 +1,79 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef _MultiMeter_h_ +#define _MultiMeter_h_ + +#include <SensorDisplay.h> + +class QGroupBox; +class QLCDNumber; +class QLabel; +class MultiMeterSettings; + +class MultiMeter : public KSGRD::SensorDisplay +{ + Q_OBJECT + +public: + MultiMeter(QWidget* parent = 0, const char* name = 0, + const QString& = QString::null, double min = 0, double max = 0, bool nf = false, bool isApplet = false); + virtual ~MultiMeter() + { + } + + bool addSensor(const QString& hostName, const QString& sensorName, + const QString& sensorType, const QString& sensorDescr); + void answerReceived(int id, const QString& answer); + void resizeEvent(QResizeEvent*); + + bool restoreSettings(QDomElement& element); + bool saveSettings(QDomDocument& doc, QDomElement& element, bool save = true); + + virtual bool hasSettingsDialog() const + { + return (true); + } + + void configureSettings(); + +public slots: + void applySettings(); + void applyStyle(); + +private: + void setDigitColor(const QColor& col); + void setBackgroundColor(const QColor& col); + + QLCDNumber* lcd; + QColor normalDigitColor; + QColor alarmDigitColor; + + MultiMeterSettings* mms; + bool lowerLimitActive; + double lowerLimit; + bool upperLimitActive; + double upperLimit; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/MultiMeterSettings.cc b/ksysguard/gui/SensorDisplayLib/MultiMeterSettings.cc new file mode 100644 index 000000000..9114c583b --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/MultiMeterSettings.cc @@ -0,0 +1,127 @@ +/* This file is part of the KDE project + Copyright ( C ) 2003 Nadeem Hasan <nhasan@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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "MultiMeterSettings.h" +#include "MultiMeterSettingsWidget.h" + +#include <klocale.h> + +MultiMeterSettings::MultiMeterSettings( QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n( "Multimeter Settings" ), + Ok|Apply|Cancel, Ok, true ) +{ + m_settingsWidget = new MultiMeterSettingsWidget( this, "m_settingsWidget" ); + setMainWidget( m_settingsWidget ); +} + +QString MultiMeterSettings::title() +{ + return m_settingsWidget->title(); +} + +bool MultiMeterSettings::showUnit() +{ + return m_settingsWidget->showUnit(); +} + +bool MultiMeterSettings::lowerLimitActive() +{ + return m_settingsWidget->lowerLimitActive(); +} + +bool MultiMeterSettings::upperLimitActive() +{ + return m_settingsWidget->upperLimitActive(); +} + +double MultiMeterSettings::lowerLimit() +{ + return m_settingsWidget->lowerLimit(); +} + +double MultiMeterSettings::upperLimit() +{ + return m_settingsWidget->upperLimit(); +} + +QColor MultiMeterSettings::normalDigitColor() +{ + return m_settingsWidget->normalDigitColor(); +} + +QColor MultiMeterSettings::alarmDigitColor() +{ + return m_settingsWidget->alarmDigitColor(); +} + +QColor MultiMeterSettings::meterBackgroundColor() +{ + return m_settingsWidget->meterBackgroundColor(); +} + +void MultiMeterSettings::setTitle( const QString &title ) +{ + m_settingsWidget->setTitle( title ); +} + +void MultiMeterSettings::setShowUnit( bool b ) +{ + m_settingsWidget->setShowUnit( b ); +} + +void MultiMeterSettings::setLowerLimitActive( bool b ) +{ + m_settingsWidget->setLowerLimitActive( b ); +} + +void MultiMeterSettings::setUpperLimitActive( bool b ) +{ + m_settingsWidget->setUpperLimitActive( b ); +} + +void MultiMeterSettings::setLowerLimit( double limit ) +{ + m_settingsWidget->setLowerLimit( limit ); +} + +void MultiMeterSettings::setUpperLimit( double limit ) +{ + m_settingsWidget->setUpperLimit( limit ); +} + +void MultiMeterSettings::setNormalDigitColor( const QColor &c ) +{ + m_settingsWidget->setNormalDigitColor( c ); +} + +void MultiMeterSettings::setAlarmDigitColor( const QColor &c ) +{ + m_settingsWidget->setAlarmDigitColor( c ); +} + +void MultiMeterSettings::setMeterBackgroundColor( const QColor &c ) +{ + m_settingsWidget->setMeterBackgroundColor( c ); +} + +#include "MultiMeterSettings.moc" + +/* vim: et sw=2 ts=2 +*/ + diff --git a/ksysguard/gui/SensorDisplayLib/MultiMeterSettings.h b/ksysguard/gui/SensorDisplayLib/MultiMeterSettings.h new file mode 100644 index 000000000..516a02128 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/MultiMeterSettings.h @@ -0,0 +1,68 @@ +/* This file is part of the KDE project + Copyright ( C ) 2003 Nadeem Hasan <nhasan@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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#ifndef MULTIMETERSETTINGS_H +#define MULTIMETERSETTINGS_H + +#include <kdialogbase.h> + +#include <qstring.h> +#include <qcolor.h> + +class MultiMeterSettingsWidget; + +class MultiMeterSettings : public KDialogBase +{ + Q_OBJECT + + public: + + MultiMeterSettings( QWidget *parent=0, const char *name=0 ); + + QString title(); + bool showUnit(); + bool lowerLimitActive(); + bool upperLimitActive(); + double lowerLimit(); + double upperLimit(); + QColor normalDigitColor(); + QColor alarmDigitColor(); + QColor meterBackgroundColor(); + + void setTitle( const QString & ); + void setShowUnit( bool ); + void setLowerLimitActive( bool ); + void setUpperLimitActive( bool ); + void setLowerLimit( double ); + void setUpperLimit( double ); + void setNormalDigitColor( const QColor & ); + void setAlarmDigitColor( const QColor & ); + void setMeterBackgroundColor( const QColor & ); + + private: + + MultiMeterSettingsWidget *m_settingsWidget; +}; + +#endif // MULTIMETERSETTINGS_H + +/* vim: et sw=2 ts=2 +*/ + diff --git a/ksysguard/gui/SensorDisplayLib/MultiMeterSettingsWidget.ui b/ksysguard/gui/SensorDisplayLib/MultiMeterSettingsWidget.ui new file mode 100644 index 000000000..7ecdef88f --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/MultiMeterSettingsWidget.ui @@ -0,0 +1,475 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>MultiMeterSettingsWidget</class> +<comment>MultiMeterSettingsWidget</comment> +<widget class="QWidget"> + <property name="name"> + <cstring>MultiMeterSettingsWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>378</width> + <height>229</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>GroupBox7</cstring> + </property> + <property name="title"> + <string>Title</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit" row="0" column="0"> + <property name="name"> + <cstring>m_title</cstring> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter the title of the display here.</string> + </property> + </widget> + <widget class="QCheckBox" row="0" column="1"> + <property name="name"> + <cstring>m_showUnit</cstring> + </property> + <property name="text"> + <string>&Show unit</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Enable this to append the unit to the title of the display.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QTabWidget"> + <property name="name"> + <cstring>TabWidget2</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Alarms</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox" row="1" column="0"> + <property name="name"> + <cstring>GroupBox1_2</cstring> + </property> + <property name="title"> + <string>Alarm for Maximum Value</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>m_upperLimitActive</cstring> + </property> + <property name="text"> + <string>E&nable alarm</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Enable the maximum value alarm.</string> + </property> + </widget> + <spacer row="0" column="1"> + <property name="name"> + <cstring>Spacer1_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="0" column="2"> + <property name="name"> + <cstring>m_lblUpperLimit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Upper limit:</string> + </property> + </widget> + <widget class="QLineEdit" row="0" column="3"> + <property name="name"> + <cstring>m_upperLimit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimumSize"> + <size> + <width>70</width> + <height>0</height> + </size> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>GroupBox1</cstring> + </property> + <property name="title"> + <string>Alarm for Minimum Value</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>m_lowerLimitActive</cstring> + </property> + <property name="text"> + <string>&Enable alarm</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Enable the minimum value alarm.</string> + </property> + </widget> + <spacer row="0" column="1"> + <property name="name"> + <cstring>Spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="0" column="2"> + <property name="name"> + <cstring>m_lblLowerLimit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Lower limit:</string> + </property> + </widget> + <widget class="QLineEdit" row="0" column="3"> + <property name="name"> + <cstring>m_lowerLimit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimumSize"> + <size> + <width>70</width> + <height>0</height> + </size> + </property> + </widget> + </grid> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Colors</string> + </attribute> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Normal digit color:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Alarm digit color:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Background color:</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_normalDigitColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>0</red> + <green>255</green> + <blue>0</blue> + </color> + </property> + </widget> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_alarmDigitColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </property> + </widget> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_backgroundColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + </vbox> + </widget> + </hbox> + </widget> + </widget> + </vbox> +</widget> +<customwidgets> + <customwidget> + <class>KColorButton</class> + <header location="local">kcolorbutton.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + <signal>destroyed()</signal> + <signal>destroyed(QObject*)</signal> + <signal>pressed()</signal> + <signal>released()</signal> + <signal>clicked()</signal> + <signal>toggled(bool)</signal> + <signal>stateChanged(int)</signal> + <signal>changed(const QColor&)</signal> + <slot access="public" specifier="">deleteLater()</slot> + <slot access="private" specifier="">cleanupEventFilter(QObject*)</slot> + <slot access="public" specifier="">setEnabled(bool)</slot> + <slot access="public" specifier="">setDisabled(bool)</slot> + <slot access="public" specifier="">setCaption(const QString&)</slot> + <slot access="public" specifier="">setIcon(const QPixmap&)</slot> + <slot access="public" specifier="">setIconText(const QString&)</slot> + <slot access="public" specifier="">setMouseTracking(bool)</slot> + <slot access="public" specifier="">setFocus()</slot> + <slot access="public" specifier="">clearFocus()</slot> + <slot access="public" specifier="">setUpdatesEnabled(bool)</slot> + <slot access="public" specifier="">update()</slot> + <slot access="public" specifier="">update(int,int,int,int)</slot> + <slot access="public" specifier="">update(const QRect&)</slot> + <slot access="public" specifier="">repaint()</slot> + <slot access="public" specifier="">repaint(bool)</slot> + <slot access="public" specifier="">repaint(int,int,int,int)</slot> + <slot access="public" specifier="">repaint(int,int,int,int,bool)</slot> + <slot access="public" specifier="">repaint(const QRect&)</slot> + <slot access="public" specifier="">repaint(const QRect&,bool)</slot> + <slot access="public" specifier="">repaint(const QRegion&)</slot> + <slot access="public" specifier="">repaint(const QRegion&,bool)</slot> + <slot access="public" specifier="">show()</slot> + <slot access="public" specifier="">hide()</slot> + <slot access="public" specifier="">setShown(bool)</slot> + <slot access="public" specifier="">setHidden(bool)</slot> + <slot access="public" specifier="">iconify()</slot> + <slot access="public" specifier="">showMinimized()</slot> + <slot access="public" specifier="">showMaximized()</slot> + <slot access="public" specifier="">showFullScreen()</slot> + <slot access="public" specifier="">showNormal()</slot> + <slot access="public" specifier="">polish()</slot> + <slot access="public" specifier="">constPolish()</slot> + <slot access="public" specifier="">close()</slot> + <slot access="public" specifier="">raise()</slot> + <slot access="public" specifier="">lower()</slot> + <slot access="public" specifier="">stackUnder(QWidget*)</slot> + <slot access="public" specifier="">move(int,int)</slot> + <slot access="public" specifier="">move(const QPoint&)</slot> + <slot access="public" specifier="">resize(int,int)</slot> + <slot access="public" specifier="">resize(const QSize&)</slot> + <slot access="public" specifier="">setGeometry(int,int,int,int)</slot> + <slot access="public" specifier="">setGeometry(const QRect&)</slot> + <slot access="public" specifier="">adjustSize()</slot> + <slot access="private" specifier="">focusProxyDestroyed()</slot> + <slot access="public" specifier="">animateClick()</slot> + <slot access="public" specifier="">toggle()</slot> + <slot access="private" specifier="">animateTimeout()</slot> + <slot access="private" specifier="">autoRepeatTimeout()</slot> + <slot access="private" specifier="">emulateClick()</slot> + <slot access="public" specifier="">setOn(bool)</slot> + <slot access="private" specifier="">popupPressed()</slot> + <slot access="protected" specifier="">chooseColor()</slot> + <property type="CString">name</property> + <property type="Bool">enabled</property> + <property type="Rect">geometry</property> + <property type="SizePolicy">sizePolicy</property> + <property type="Size">minimumSize</property> + <property type="Size">maximumSize</property> + <property type="Size">sizeIncrement</property> + <property type="Size">baseSize</property> + <property type="Color">paletteForegroundColor</property> + <property type="Color">paletteBackgroundColor</property> + <property type="Pixmap">paletteBackgroundPixmap</property> + <property type="Palette">palette</property> + <property type="BackgroundOrigin">backgroundOrigin</property> + <property type="Font">font</property> + <property type="Cursor">cursor</property> + <property type="String">caption</property> + <property type="Pixmap">icon</property> + <property type="String">iconText</property> + <property type="Bool">mouseTracking</property> + <property type="FocusPolicy">focusPolicy</property> + <property type="Bool">acceptDrops</property> + <property type="String">text</property> + <property type="Pixmap">pixmap</property> + <property type="KeySequence">accel</property> + <property type="Bool">autoRepeat</property> + <property type="Bool">autoDefault</property> + <property type="Bool">default</property> + <property type="IconSet">iconSet</property> + <property type="Bool">toggleButton</property> + <property type="Bool">on</property> + <property type="Bool">flat</property> + <property type="Bool">autoMask</property> + <property type="Color">color</property> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="PNG" length="827">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000030249444154789cad953188db6614c77f0e1a9ee0029fc10509ae20c30de7d1852e4733f846d30c2e74483aa5812ea54bba35590a693a640e1d0e0e0ae16e282443e1321cd499eca5d4072951e10af26090e00ef40d013d88411d3ed967f91228e4de22f4e97dbff7d7ff7b7a6a9465c9221a8d0657116559d258801ffcf080ce76076b6d996629f99bfc7f41acb524a709e33fc73067a9cc5b287dfaeb53c28f294dbb2042d1b9228b0ccf25fbd5b598afec9ec33401dd13262fb50407f7562a97a65d90d923f23c0114df578ab7423613f2730584660bda6d453640ab02721dc210262b6fb204a7594a8456508bef0baf5f1986bf5be2130b68952944dbc2eec0b0d303e66e5da46ed1129cbfc9d1b92ea1a3211cfc92b94d1b427bdb201ea43365fa8fb2ff73463635dcbe232b45df01765ac0f7e1f52ba9a04aeff380fe40687e0488a21a327a5170b097717498110411fd2f9b80ad81afad9729de0ac3e77609fdea1ba1195a104b7e26fcf13ca73ff0f9fabb00109e1d5aecf9bac4f55b0fb29910ff6d31c6d01f0878163c506bd87facc42796fc0ceede6b323e76b971ec6c7abf62a84e5f09a3eaf52be89347ee104d4bf8e48620a6a0d37527964eb532f23d60d7a72e41c4799aa786278f94f8c4151481f6a6ef9e7b0b985cb2e292e266cb25263345b5c9f8254ea91182c090cd2c0fefa7c49326e9a9eb8630f2d731f53ac5dc357fb4254cff55462f0afab77cf233c3ce0d21dcf479781fb2a9e5a76f135415d312badd8274566fb94b8a6503fa0303c0c15ec6e8b8e0eebd26dd1e44dd9cef7f6c630283b5169d2bbb838070eb92e07567dc67bad3836c66787698b1ff38637c2c743a0202e9698a9eeb72e75f434b723344bcfa87b23a2b2ee0285fdc114c1071f49beb86f8e4a2b86909fd41c46868b1aaa882b5752b96e0e434619a00d72fe0fd81b0d30b8963433a75ebe1a64ff7d382700b766f864ea497134feae04659966ec07b94ddcf8430ac5a6dce7264caa20d6bc629e209d6423c51d24cb16eb434ea6017251f16f541ffae071f1ad7c0fda3ae3a967d7c95f0b22cf90f71e859c3d57176e60000000049454e44ae426082</data> + </image> +</images> +<connections> + <connection> + <sender>m_lowerLimitActive</sender> + <signal>toggled(bool)</signal> + <receiver>m_lowerLimit</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_upperLimitActive</sender> + <signal>toggled(bool)</signal> + <receiver>m_upperLimit</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_lowerLimitActive</sender> + <signal>toggled(bool)</signal> + <receiver>m_lblLowerLimit</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_upperLimitActive</sender> + <signal>toggled(bool)</signal> + <receiver>m_lblUpperLimit</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<includes> + <include location="global" impldecl="in implementation">kdialog.h</include> + <include location="global" impldecl="in implementation">knumvalidator.h</include> + <include location="local" impldecl="in implementation">MultiMeterSettingsWidget.ui.h</include> +</includes> +<slots> + <slot>setMeterBackgroundColor( const QColor & c )</slot> +</slots> +<functions> + <function access="private" specifier="non virtual">init()</function> + <function specifier="non virtual" returnType="QString">title()</function> + <function specifier="non virtual" returnType="bool">showUnit()</function> + <function returnType="bool">lowerLimitActive()</function> + <function specifier="non virtual" returnType="double">lowerLimit()</function> + <function returnType="bool">upperLimitActive()</function> + <function returnType="double">upperLimit()</function> + <function specifier="non virtual" returnType="QColor">normalDigitColor()</function> + <function specifier="non virtual" returnType="QColor">alarmDigitColor()</function> + <function returnType="QColor">meterBackgroundColor()</function> + <function specifier="non virtual">setTitle( const QString & s )</function> + <function specifier="non virtual">setShowUnit( bool b )</function> + <function specifier="non virtual">setLowerLimitActive( bool b )</function> + <function specifier="non virtual">setLowerLimit( double d )</function> + <function specifier="non virtual">setUpperLimitActive( bool b )</function> + <function specifier="non virtual">setUpperLimit( double d )</function> + <function specifier="non virtual">setNormalDigitColor( const QColor & c )</function> + <function specifier="non virtual">setAlarmDigitColor( const QColor & c )</function> +</functions> +<layoutdefaults spacing="6" margin="11"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +<includehints> + <includehint>kcolorbutton.h</includehint> +</includehints> +</UI> diff --git a/ksysguard/gui/SensorDisplayLib/MultiMeterSettingsWidget.ui.h b/ksysguard/gui/SensorDisplayLib/MultiMeterSettingsWidget.ui.h new file mode 100644 index 000000000..81d6e73f6 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/MultiMeterSettingsWidget.ui.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + +void MultiMeterSettingsWidget::init() +{ + m_lowerLimit->setValidator(new KDoubleValidator(m_lowerLimit)); + m_upperLimit->setValidator(new KDoubleValidator(m_upperLimit)); + + m_title->setFocus(); +} + +QString MultiMeterSettingsWidget::title() +{ + return m_title->text(); +} + + +bool MultiMeterSettingsWidget::showUnit() +{ + return m_showUnit->isChecked(); +} + + +bool MultiMeterSettingsWidget::lowerLimitActive() +{ + return m_lowerLimitActive->isChecked(); +} + + +double MultiMeterSettingsWidget::lowerLimit() +{ + return m_lowerLimit->text().toDouble(); +} + + +bool MultiMeterSettingsWidget::upperLimitActive() +{ + return m_upperLimitActive->isChecked(); +} + + +double MultiMeterSettingsWidget::upperLimit() +{ + return m_upperLimit->text().toDouble(); +} + + +QColor MultiMeterSettingsWidget::normalDigitColor() +{ + return m_normalDigitColor->color(); +} + + +QColor MultiMeterSettingsWidget::alarmDigitColor() +{ + return m_alarmDigitColor->color(); +} + + +QColor MultiMeterSettingsWidget::meterBackgroundColor() +{ + return m_backgroundColor->color(); +} + + +void MultiMeterSettingsWidget::setTitle( const QString &s ) +{ + m_title->setText(s); +} + + +void MultiMeterSettingsWidget::setShowUnit( bool b ) +{ + m_showUnit->setChecked(b); +} + + +void MultiMeterSettingsWidget::setLowerLimitActive( bool b ) +{ + m_lowerLimitActive->setChecked(b); +} + + +void MultiMeterSettingsWidget::setLowerLimit( double d ) +{ + m_lowerLimit->setText(QString("%1").arg(d)); +} + + +void MultiMeterSettingsWidget::setUpperLimitActive( bool b ) +{ + m_upperLimitActive->setChecked(b); +} + + +void MultiMeterSettingsWidget::setUpperLimit( double d ) +{ + m_upperLimit->setText(QString("%1").arg(d)); +} + + +void MultiMeterSettingsWidget::setNormalDigitColor( const QColor &c ) +{ + m_normalDigitColor->setColor(c); +} + + +void MultiMeterSettingsWidget::setAlarmDigitColor( const QColor &c ) +{ + m_alarmDigitColor->setColor(c); +} + + +void MultiMeterSettingsWidget::setMeterBackgroundColor( const QColor &c ) +{ + m_backgroundColor->setColor(c); +} diff --git a/ksysguard/gui/SensorDisplayLib/ProcessController.cc b/ksysguard/gui/SensorDisplayLib/ProcessController.cc new file mode 100644 index 000000000..b9fcd4f06 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ProcessController.cc @@ -0,0 +1,472 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms version 2 of of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <assert.h> + +#include <qtimer.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kdialogbase.h> +#include <klistviewsearchline.h> + +#include <ksgrd/SensorManager.h> + +#include "ProcessController.moc" +#include "SignalIDs.h" + +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qgroupbox.h> +#include <qlayout.h> + +#include <kapplication.h> +#include <kpushbutton.h> + + + +ProcessController::ProcessController(QWidget* parent, const char* name, const QString &title, bool nf) + : KSGRD::SensorDisplay(parent, name, title, nf) +{ + dict.setAutoDelete(true); + dict.insert("Name", new QString(i18n("Name"))); + dict.insert("PID", new QString(i18n("PID"))); + dict.insert("PPID", new QString(i18n("PPID"))); + dict.insert("UID", new QString(i18n("UID"))); + dict.insert("GID", new QString(i18n("GID"))); + dict.insert("Status", new QString(i18n("Status"))); + dict.insert("User%", new QString(i18n("User%"))); + dict.insert("System%", new QString(i18n("System%"))); + dict.insert("Nice", new QString(i18n("Nice"))); + dict.insert("VmSize", new QString(i18n("VmSize"))); + dict.insert("VmRss", new QString(i18n("VmRss"))); + dict.insert("Login", new QString(i18n("Login"))); + dict.insert("Command", new QString(i18n("Command"))); + + // Setup the geometry management. + gm = new QVBoxLayout(this, 10); + Q_CHECK_PTR(gm); + gm->addSpacing(15); + + gmSearch = new QHBoxLayout(); + Q_CHECK_PTR(gmSearch); + gm->addLayout(gmSearch, 0); + + // Create the table that lists the processes. + pList = new ProcessList(this, "pList"); + Q_CHECK_PTR(pList); + pList->setShowSortIndicator(true); + pListSearchLine = new KListViewSearchLineWidget(pList, this, "process_list_search_line"); + gmSearch->addWidget(pListSearchLine, 1); + + connect(pList, SIGNAL(killProcess(int, int)), + this, SLOT(killProcess(int, int))); + connect(pList, SIGNAL(reniceProcess(const QValueList<int> &, int)), + this, SLOT(reniceProcess(const QValueList<int> &, int))); + connect(pList, SIGNAL(listModified(bool)), + this, SLOT(setModified(bool))); + + /* Create the combo box to configure the process filter. The + * cbFilter must be created prior to constructing pList as the + * pList constructor sets cbFilter to its start value. */ + cbFilter = new QComboBox(this, "pList_cbFilter"); + Q_CHECK_PTR(cbFilter); + gmSearch->addWidget(cbFilter,0); + cbFilter->insertItem(i18n("All Processes"), 0); + cbFilter->insertItem(i18n("System Processes"), 1); + cbFilter->insertItem(i18n("User Processes"), 2); + cbFilter->insertItem(i18n("Own Processes"), 3); + cbFilter->setMinimumSize(cbFilter->sizeHint()); + // Create the check box to switch between tree view and list view. + xbTreeView = new QCheckBox(i18n("&Tree"), this, "xbTreeView"); + Q_CHECK_PTR(xbTreeView); + xbTreeView->setMinimumSize(xbTreeView->sizeHint()); + connect(xbTreeView, SIGNAL(toggled(bool)), + this, SLOT(setTreeView(bool))); + + + /* When the both cbFilter and pList are constructed we can connect the + * missing link. */ + connect(cbFilter, SIGNAL(activated(int)), + this, SLOT(filterModeChanged(int))); + + // Create the 'Refresh' button. + bRefresh = new KPushButton( KGuiItem( i18n( "&Refresh" ), "reload" ), + this, "bRefresh" ); + Q_CHECK_PTR(bRefresh); + bRefresh->setMinimumSize(bRefresh->sizeHint()); + connect(bRefresh, SIGNAL(clicked()), this, SLOT(updateList())); + + // Create the 'Kill' button. + bKill = new KPushButton(i18n("&Kill"), this, "bKill"); + Q_CHECK_PTR(bKill); + bKill->setMinimumSize(bKill->sizeHint()); + connect(bKill, SIGNAL(clicked()), this, SLOT(killProcess())); + /* Disable the kill button until we know that the daemon supports the + * kill command. */ + bKill->setEnabled(false); + killSupported = false; + + gm->addWidget(pList, 1); + + gm1 = new QHBoxLayout(); + Q_CHECK_PTR(gm1); + gm->addLayout(gm1, 0); + gm1->addStretch(); + gm1->addWidget(xbTreeView); + gm1->addStretch(); + gm1->addWidget(bRefresh); + gm1->addStretch(); + gm1->addWidget(bKill); + gm1->addStretch(); + gm->addSpacing(5); + + gm->activate(); + + setPlotterWidget(pList); + + setMinimumSize(sizeHint()); + fixTabOrder(); +} + +void ProcessController::setSearchFocus() { + //stupid search line widget. See rant in fixTabOrder + if(!pListSearchLine->searchLine()) + QTimer::singleShot(100, this, SLOT(setSearchFocus())); + else { + pListSearchLine->searchLine()->setFocus(); + } +} +void ProcessController::fixTabOrder() { + + //Wow, I hate this search line widget so much. + //It creates the searchline in a singleshot timer. This makes it totally unpredictable when searchLine is actually valid. + //So we set up singleshot timer and call ourselves over and over until it's ready. + // + //Did i mention I hate this? + if(!pListSearchLine->searchLine()) + QTimer::singleShot(100, this, SLOT(fixTabOrder())); + else { + setTabOrder(pListSearchLine->searchLine(), cbFilter); + setTabOrder(cbFilter, pList); + setTabOrder(pList, xbTreeView); + setTabOrder(xbTreeView, bRefresh); + setTabOrder(bRefresh, bKill); + } +} + +void +ProcessController::resizeEvent(QResizeEvent* ev) +{ + if(frame()) + frame()->setGeometry(0, 0, width(), height()); + + QWidget::resizeEvent(ev); +} + +bool +ProcessController::addSensor(const QString& hostName, + const QString& sensorName, + const QString& sensorType, + const QString& title) +{ + if (sensorType != "table") + return (false); + + registerSensor(new KSGRD::SensorProperties(hostName, sensorName, sensorType, title)); + /* This just triggers the first communication. The full set of + * requests are send whenever the sensor reconnects (detected in + * sensorError(). */ + + sendRequest(hostName, "test kill", 4); + + if (title.isEmpty()) + setTitle(i18n("%1: Running Processes").arg(hostName)); + else + setTitle(title); + + return (true); +} + +void +ProcessController::updateList() +{ + sendRequest(sensors().at(0)->hostName(), "ps", 2); +} + +void +ProcessController::killProcess(int pid, int sig) +{ + sendRequest(sensors().at(0)->hostName(), + QString("kill %1 %2" ).arg(pid).arg(sig), 3); + + if ( !timerOn() ) + // give ksysguardd time to update its proccess list + QTimer::singleShot(3000, this, SLOT(updateList())); + else + updateList(); +} + +void +ProcessController::killProcess() +{ + const QStringList& selectedAsStrings = pList->getSelectedAsStrings(); + if (selectedAsStrings.isEmpty()) + { + KMessageBox::sorry(this, + i18n("You need to select a process first.")); + return; + } + else + { + QString msg = i18n("Do you want to kill the selected process?", + "Do you want to kill the %n selected processes?", + selectedAsStrings.count()); + + KDialogBase *dlg = new KDialogBase ( i18n ("Kill Process"), + KDialogBase::Yes | KDialogBase::Cancel, + KDialogBase::Yes, KDialogBase::Cancel, this->parentWidget(), + "killconfirmation", + true, true, KGuiItem(i18n("Kill"))); + + bool dontAgain = false; + + int res = KMessageBox::createKMessageBox(dlg, QMessageBox::Question, + msg, selectedAsStrings, + i18n("Do not ask again"), &dontAgain, + KMessageBox::Notify); + + if (res != KDialogBase::Yes) + { + return; + } + } + + const QValueList<int>& selectedPIds = pList->getSelectedPIds(); + + // send kill signal to all seleted processes + QValueListConstIterator<int> it; + for (it = selectedPIds.begin(); it != selectedPIds.end(); ++it) + sendRequest(sensors().at(0)->hostName(), QString("kill %1 %2" ).arg(*it) + .arg(MENU_ID_SIGKILL), 3); + + if ( !timerOn()) + // give ksysguardd time to update its proccess list + QTimer::singleShot(3000, this, SLOT(updateList())); + else + updateList(); +} + +void +ProcessController::reniceProcess(const QValueList<int> &pids, int niceValue) +{ + for( QValueList<int>::ConstIterator it = pids.constBegin(), end = pids.constEnd(); it != end; ++it ) + sendRequest(sensors().at(0)->hostName(), + QString("setpriority %1 %2" ).arg(*it).arg(niceValue), 5); + sendRequest(sensors().at(0)->hostName(), "ps", 2); //update the display afterwards +} + +void +ProcessController::answerReceived(int id, const QString& answer) +{ + /* We received something, so the sensor is probably ok. */ + sensorError(id, false); + + switch (id) + { + case 1: + { + /* We have received the answer to a ps? command that contains + * the information about the table headers. */ + KSGRD::SensorTokenizer lines(answer, '\n'); + if (lines.count() != 2) + { + kdDebug (1215) << "ProcessController::answerReceived(1)" + "wrong number of lines [" << answer << "]" << endl; + sensorError(id, true); + return; + } + KSGRD::SensorTokenizer headers(lines[0], '\t'); + KSGRD::SensorTokenizer colTypes(lines[1], '\t'); + + pList->removeColumns(); + for (unsigned int i = 0; i < headers.count(); i++) + { + QString header; + if (dict[headers[i]]) + header = *dict[headers[i]]; + else + header = headers[i]; + pList->addColumn(header, colTypes[i]); + } + + break; + } + case 2: + /* We have received the answer to a ps command that contains a + * list of processes with various additional information. */ + pList->update(answer); + pListSearchLine->searchLine()->updateSearch(); //re-apply the filter + break; + case 3: + { + // result of kill operation + kdDebug(1215) << answer << endl; + KSGRD::SensorTokenizer vals(answer, '\t'); + switch (vals[0].toInt()) + { + case 0: // successful kill operation + break; + case 1: // unknown error + KSGRD::SensorMgr->notify( + i18n("Error while attempting to kill process %1.") + .arg(vals[1])); + break; + case 2: + KSGRD::SensorMgr->notify( + i18n("Insufficient permissions to kill " + "process %1.").arg(vals[1])); + break; + case 3: + KSGRD::SensorMgr->notify( + i18n("Process %1 has already disappeared.") + .arg(vals[1])); + break; + case 4: + KSGRD::SensorMgr->notify(i18n("Invalid Signal.")); + break; + } + break; + } + case 4: + killSupported = (answer.toInt() == 1); + pList->setKillSupported(killSupported); + bKill->setEnabled(killSupported); + break; + case 5: + { + // result of renice operation + kdDebug(1215) << answer << endl; + KSGRD::SensorTokenizer vals(answer, '\t'); + switch (vals[0].toInt()) + { + case 0: // successful renice operation + break; + case 1: // unknown error + KSGRD::SensorMgr->notify( + i18n("Error while attempting to renice process %1.") + .arg(vals[1])); + break; + case 2: + KSGRD::SensorMgr->notify( + i18n("Insufficient permissions to renice " + "process %1.").arg(vals[1])); + break; + case 3: + KSGRD::SensorMgr->notify( + i18n("Process %1 has already disappeared.") + .arg(vals[1])); + break; + case 4: + KSGRD::SensorMgr->notify(i18n("Invalid argument.")); + break; + } + break; + } + } +} + +void +ProcessController::sensorError(int, bool err) +{ + if (err == sensors().at(0)->isOk()) + { + if (!err) + { + /* Whenever the communication with the sensor has been + * (re-)established we need to requests the full set of + * properties again, since the back-end might be a new + * one. */ + sendRequest(sensors().at(0)->hostName(), "test kill", 4); + sendRequest(sensors().at(0)->hostName(), "ps?", 1); + sendRequest(sensors().at(0)->hostName(), "ps", 2); + } + + /* This happens only when the sensorOk status needs to be changed. */ + sensors().at(0)->setIsOk( !err ); + } + setSensorOk(sensors().at(0)->isOk()); +} + +bool +ProcessController::restoreSettings(QDomElement& element) +{ + bool result = addSensor(element.attribute("hostName"), + element.attribute("sensorName"), (element.attribute("sensorType").isEmpty() ? "table" : element.attribute("sensorType")), + QString::null); + + xbTreeView->setChecked(element.attribute("tree").toInt()); + setTreeView(element.attribute("tree").toInt()); + + uint filter = element.attribute("filter").toUInt(); + cbFilter->setCurrentItem(filter); + filterModeChanged(filter); + + uint col = element.attribute("sortColumn").toUInt(); + bool inc = element.attribute("incrOrder").toUInt(); + + if (!pList->load(element)) + return (false); + + pList->setSortColumn(col, inc); + + SensorDisplay::restoreSettings(element); + + setModified(false); + + return (result); +} + +bool +ProcessController::saveSettings(QDomDocument& doc, QDomElement& element, bool save) +{ + element.setAttribute("hostName", sensors().at(0)->hostName()); + element.setAttribute("sensorName", sensors().at(0)->name()); + element.setAttribute("sensorType", sensors().at(0)->type()); + element.setAttribute("tree", (uint) xbTreeView->isChecked()); + element.setAttribute("filter", cbFilter->currentItem()); + element.setAttribute("sortColumn", pList->getSortColumn()); + element.setAttribute("incrOrder", pList->getIncreasing()); + + if (!pList->save(doc, element)) + return (false); + + SensorDisplay::saveSettings(doc, element); + + if (save) + setModified(false); + + return (true); +} diff --git a/ksysguard/gui/SensorDisplayLib/ProcessController.h b/ksysguard/gui/SensorDisplayLib/ProcessController.h new file mode 100644 index 000000000..f834efbb6 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ProcessController.h @@ -0,0 +1,154 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef _ProcessController_h_ +#define _ProcessController_h_ + +#include <qdict.h> +#include <qwidget.h> + +#include <kapplication.h> + +#include <SensorDisplay.h> + +#include "ProcessList.h" + +class QVBoxLayout; +class QHBoxLayout; +class QCheckBox; +class QComboBox; +class KPushButton; +class KListViewSearchLineWidget; + +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 ProcessController : public KSGRD::SensorDisplay +{ + Q_OBJECT + +public: + ProcessController(QWidget* parent = 0, const char* name = 0, const QString &title = QString::null, bool nf = false); + virtual ~ProcessController() { } + + void resizeEvent(QResizeEvent*); + + bool restoreSettings(QDomElement& element); + + bool saveSettings(QDomDocument& doc, QDomElement& element, bool save = true); + + void refreshList(void) + { + updateList(); + } + + virtual void timerEvent(QTimerEvent*) + { + updateList(); + } + + virtual bool addSensor(const QString&, const QString&, const QString&, const QString&); + + virtual void answerReceived(int id, const QString& answer); + + virtual void sensorError(int, bool err); + + void configureSettings() { } + + virtual bool hasSettingsDialog() const + { + return (false); + } + +public slots: + void setSearchFocus(); + void fixTabOrder(); + void filterModeChanged(int filter) + { + pList->setFilterMode(filter); + updateList(); + setModified(true); + } + + void setTreeView(bool tv) + { + pList->setTreeView(tv); + updateList(); + setModified(true); + } + + virtual void setModified(bool mfd) + { + if (mfd != modified()) + { + SensorDisplay::setModified( mfd ); + if (!mfd) + pList->setModified(0); + emit modified(modified()); + } + } + + void killProcess(); + void killProcess(int pid, int sig); + + void reniceProcess(const QValueList<int> &pids, int niceValue); + + void updateList(); + +signals: + void setFilterMode(int); + +private: + QVBoxLayout* gm; + + bool killSupported; + + /// The process list. + ProcessList* pList; + ///Layout for the search line and process filter combo box + QHBoxLayout* gmSearch; + KListViewSearchLineWidget *pListSearchLine; + + QHBoxLayout* gm1; + + /// Checkbox to switch between tree and list view + QCheckBox* xbTreeView; + + /// This combo boxes control the process filter. + QComboBox* cbFilter; + + /// These buttons force an immedeate refresh or kill a process. + KPushButton* bRefresh; + KPushButton* bKill; + + /// Dictionary for header translations. + QDict<QString> dict; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/ProcessList.cc b/ksysguard/gui/SensorDisplayLib/ProcessList.cc new file mode 100644 index 000000000..6d158c872 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ProcessList.cc @@ -0,0 +1,941 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (C) 1997 Bernd Johannes Wuebben + <wuebben@math.cornell.edu> + + Copyright (C) 1998 Nicolas Leclercq <nicknet@planete.net> + + Copyright (c) 1999, 2000, 2001, 2002 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <assert.h> +#include <config.h> +#include <ctype.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +#include <qbitmap.h> +#include <qheader.h> +#include <qimage.h> +#include <qpopupmenu.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kmessagebox.h> + +#include "ProcessController.h" +#include "ProcessList.h" +#include "ReniceDlg.h" +#include "SignalIDs.h" + +#define NONE -1 +#define INIT_PID 1 + +//extern const char* intKey(const char* text); +//extern const char* timeKey(const char* text); +//extern const char* floatKey(const char* text); + +QDict<QString> ProcessList::aliases; + +int ProcessLVI::compare( QListViewItem *item, int col, bool ascending ) const +{ + int type = ((ProcessList*)listView())->columnType( col ); + + if ( type == ProcessList::Int ) { + int prev = (int)KGlobal::locale()->readNumber( key( col, ascending ) ); + int next = (int)KGlobal::locale()->readNumber( item->key( col, ascending ) ); + if ( prev < next ) + return -1; + else if ( prev == next ) + return 0; + else + return 1; + } + + if ( type == ProcessList::Float ) { + double prev = KGlobal::locale()->readNumber( key( col, ascending ) ); + double next = KGlobal::locale()->readNumber( item->key( col, ascending ) ); + if ( prev < next ) + return -1; + else + return 1; + } + + if ( type == ProcessList::Time ) { + int hourPrev, hourNext, minutesPrev, minutesNext; + sscanf( key( col, ascending ).latin1(), "%d:%d", &hourPrev, &minutesPrev ); + sscanf( item->key( col, ascending ).latin1(), "%d:%d", &hourNext, &minutesNext ); + int prev = hourPrev * 60 + minutesPrev; + int next = hourNext * 60 + minutesNext; + if ( prev < next ) + return -1; + else if ( prev == next ) + return 0; + else + return 1; + } + + return key( col, ascending ).localeAwareCompare( item->key( col, ascending ) ); +} + +ProcessList::ProcessList(QWidget *parent, const char* name) + : KListView(parent, name) +{ + iconCache.setAutoDelete(true); + + columnDict.setAutoDelete(true); + columnDict.insert("running", + new QString(i18n("process status", "running"))); + columnDict.insert("sleeping", + new QString(i18n("process status", "sleeping"))); + columnDict.insert("disk sleep", + new QString(i18n("process status", "disk sleep"))); + columnDict.insert("zombie", new QString(i18n("process status", "zombie"))); + columnDict.insert("stopped", + new QString(i18n("process status", "stopped"))); + columnDict.insert("paging", new QString(i18n("process status", "paging"))); + columnDict.insert("idle", new QString(i18n("process status", "idle"))); + + if (aliases.isEmpty()) + { +#ifdef Q_OS_LINUX + aliases.insert("init", new QString("penguin")); +#else + aliases.insert("init", new QString("system")); +#endif + /* kernel stuff */ + aliases.insert("bdflush", new QString("kernel")); + aliases.insert("dhcpcd", new QString("kernel")); + aliases.insert("kapm-idled", new QString("kernel")); + aliases.insert("keventd", new QString("kernel")); + aliases.insert("khubd", new QString("kernel")); + aliases.insert("klogd", new QString("kernel")); + aliases.insert("kreclaimd", new QString("kernel")); + aliases.insert("kreiserfsd", new QString("kernel")); + aliases.insert("ksoftirqd_CPU0", new QString("kernel")); + aliases.insert("ksoftirqd_CPU1", new QString("kernel")); + aliases.insert("ksoftirqd_CPU2", new QString("kernel")); + aliases.insert("ksoftirqd_CPU3", new QString("kernel")); + aliases.insert("ksoftirqd_CPU4", new QString("kernel")); + aliases.insert("ksoftirqd_CPU5", new QString("kernel")); + aliases.insert("ksoftirqd_CPU6", new QString("kernel")); + aliases.insert("ksoftirqd_CPU7", new QString("kernel")); + aliases.insert("kswapd", new QString("kernel")); + aliases.insert("kupdated", new QString("kernel")); + aliases.insert("mdrecoveryd", new QString("kernel")); + aliases.insert("scsi_eh_0", new QString("kernel")); + aliases.insert("scsi_eh_1", new QString("kernel")); + aliases.insert("scsi_eh_2", new QString("kernel")); + aliases.insert("scsi_eh_3", new QString("kernel")); + aliases.insert("scsi_eh_4", new QString("kernel")); + aliases.insert("scsi_eh_5", new QString("kernel")); + aliases.insert("scsi_eh_6", new QString("kernel")); + aliases.insert("scsi_eh_7", new QString("kernel")); + /* daemon and other service providers */ + aliases.insert("artsd", new QString("daemon")); + aliases.insert("atd", new QString("daemon")); + aliases.insert("automount", new QString("daemon")); + aliases.insert("cardmgr", new QString("daemon")); + aliases.insert("cron", new QString("daemon")); + aliases.insert("cupsd", new QString("daemon")); + aliases.insert("in.identd", new QString("daemon")); + aliases.insert("lpd", new QString("daemon")); + aliases.insert("mingetty", new QString("daemon")); + aliases.insert("nscd", new QString("daemon")); + aliases.insert("portmap", new QString("daemon")); + aliases.insert("rpc.statd", new QString("daemon")); + aliases.insert("rpciod", new QString("daemon")); + aliases.insert("sendmail", new QString("daemon")); + aliases.insert("sshd", new QString("daemon")); + aliases.insert("syslogd", new QString("daemon")); + aliases.insert("usbmgr", new QString("daemon")); + aliases.insert("wwwoffled", new QString("daemon")); + aliases.insert("xntpd", new QString("daemon")); + aliases.insert("ypbind", new QString("daemon")); + /* kde applications */ + aliases.insert("appletproxy", new QString("kdeapp")); + aliases.insert("dcopserver", new QString("kdeapp")); + aliases.insert("kcookiejar", new QString("kdeapp")); + aliases.insert("kde", new QString("kdeapp")); + aliases.insert("kded", new QString("kdeapp")); + aliases.insert("kdeinit", new QString("kdeapp")); + aliases.insert("kdesktop", new QString("kdeapp")); + aliases.insert("kdesud", new QString("kdeapp")); + aliases.insert("kdm", new QString("kdeapp")); + aliases.insert("khotkeys", new QString("kdeapp")); + aliases.insert("kio_file", new QString("kdeapp")); + aliases.insert("kio_uiserver", new QString("kdeapp")); + aliases.insert("klauncher", new QString("kdeapp")); + aliases.insert("ksmserver", new QString("kdeapp")); + aliases.insert("kwrapper", new QString("kdeapp")); + aliases.insert("kwrited", new QString("kdeapp")); + aliases.insert("kxmlrpcd", new QString("kdeapp")); + aliases.insert("startkde", new QString("kdeapp")); + /* other processes */ + aliases.insert("bash", new QString("shell")); + aliases.insert("cat", new QString("tools")); + aliases.insert("egrep", new QString("tools")); + aliases.insert("emacs", new QString("wordprocessing")); + aliases.insert("fgrep", new QString("tools")); + aliases.insert("find", new QString("tools")); + aliases.insert("grep", new QString("tools")); + aliases.insert("ksh", new QString("shell")); + aliases.insert("screen", new QString("openterm")); + aliases.insert("sh", new QString("shell")); + aliases.insert("sort", new QString("tools")); + aliases.insert("ssh", new QString("shell")); + aliases.insert("su", new QString("tools")); + aliases.insert("tcsh", new QString("shell")); + aliases.insert("tee", new QString("tools")); + aliases.insert("vi", new QString("wordprocessing")); + } + + /* The filter mode is controlled by a combo box of the parent. If + * the mode is changed we get a signal. */ + connect(parent, SIGNAL(setFilterMode(int)), + this, SLOT(setFilterMode(int))); + + /* We need to catch this signal to show various popup menues. */ + connect(this, + SIGNAL(rightButtonPressed(QListViewItem*, const QPoint&, int)), + this, + SLOT(handleRMBPressed(QListViewItem*, const QPoint&, int))); + + /* Since Qt does not tell us the sorting details we have to do our + * own bookkeping, so we can save and restore the sorting + * settings. */ + connect(header(), SIGNAL(clicked(int)), this, SLOT(sortingChanged(int))); + + treeViewEnabled = false; + openAll = true; + + filterMode = FILTER_ALL; + + sortColumn = 1; + increasing = false; + + // Elements in the process list may only live in this list. + pl.setAutoDelete(true); + + setItemMargin(2); + setAllColumnsShowFocus(true); + setTreeStepSize(17); + setSorting(sortColumn, increasing); + setSelectionMode(QListView::Extended); + + // Create popup menu for RMB clicks on table header + headerPM = new QPopupMenu(); + headerPM->insertItem(i18n("Remove Column"), HEADER_REMOVE); + headerPM->insertItem(i18n("Add Column"), HEADER_ADD); + headerPM->insertItem(i18n("Help on Column"), HEADER_HELP); + + connect(header(), SIGNAL(sizeChange(int, int, int)), + this, SLOT(sizeChanged(int, int, int))); + connect(header(), SIGNAL(indexChange(int, int, int)), + this, SLOT(indexChanged(int, int, int))); + + killSupported = false; + setModified(false); +} + +ProcessList::~ProcessList() +{ + delete(headerPM); +} + +const QValueList<int>& +ProcessList::getSelectedPIds() +{ + selectedPIds.clear(); + // iterate through all selected visible items of the listview + QListViewItemIterator it(this, QListViewItemIterator::Visible | QListViewItemIterator::Selected ); + for ( ; it.current(); ++it ) + selectedPIds.append(it.current()->text(1).toInt()); + + return (selectedPIds); +} + +const QStringList& +ProcessList::getSelectedAsStrings() +{ + selectedAsStrings.clear(); + // iterate through all selected visible items of the listview + QListViewItemIterator it(this, QListViewItemIterator::Visible | QListViewItemIterator::Selected ); + QString spaces; + for ( ; it.current(); ++it ) { + spaces.fill(QChar(' '), 7 - it.current()->text(1).length()); + selectedAsStrings.append("(PID: " + it.current()->text(1) + ")" + spaces + " " + it.current()->text(0)); + } + + return (selectedAsStrings); +} +bool +ProcessList::update(const QString& list) +{ + /* Disable painting to avoid flickering effects, + * especially when in tree view mode. + * Ditto for the scrollbar. */ + setUpdatesEnabled(false); + viewport()->setUpdatesEnabled(false); + + pl.clear(); + + // Convert ps answer in a list of tokenized lines + KSGRD::SensorTokenizer procs(list, '\n'); + for (unsigned int i = 0; i < procs.count(); i++) + { + KSGRD::SensorPSLine* line = new KSGRD::SensorPSLine(procs[i]); + if (line->count() != (uint) columns()) + { +#if 0 + // This is needed for debugging only. + kdDebug(1215) << list << endl; + QString l; + for (uint j = 0; j < line->count(); j++) + l += (*line)[j] + "|"; + kdDebug(1215) << "Incomplete ps line:" << l << endl; +#endif + return (false); + } + else + pl.append(line); + } + + int currItemPos = itemPos(currentItem()); + int vpos = verticalScrollBar()->value(); + int hpos = horizontalScrollBar()->value(); + + updateMetaInfo(); + + clear(); + + if (treeViewEnabled) + buildTree(); + else + buildList(); + + QListViewItemIterator it( this ); + while ( it.current() ) { + if ( itemPos( it.current() ) == currItemPos ) { + setCurrentItem( it.current() ); + break; + } + ++it; + } + + verticalScrollBar()->setValue(vpos); + horizontalScrollBar()->setValue(hpos); + + // Re-enable painting, and force an update. + setUpdatesEnabled(true); + viewport()->setUpdatesEnabled(true); + + triggerUpdate(); + + return (true); +} + +void +ProcessList::setTreeView(bool tv) +{ + if (treeViewEnabled = tv) + { + savedWidth[0] = columnWidth(0); + openAll = true; + } + else + { + /* In tree view the first column is wider than in list view mode. + * So we shrink it to 1 pixel. The next update will resize it again + * appropriately. */ + setColumnWidth(0, savedWidth[0]); + } + /* In tree view mode borders are added to the icons. So we have to clear + * the cache when we change the tree view mode. */ + iconCache.clear(); +} + +bool +ProcessList::load(QDomElement& el) +{ + QDomNodeList dnList = el.elementsByTagName("column"); + for (uint i = 0; i < dnList.count(); ++i) + { + QDomElement lel = dnList.item(i).toElement(); + if (savedWidth.count() <= i) + savedWidth.append(lel.attribute("savedWidth").toInt()); + else + savedWidth[i] = lel.attribute("savedWidth").toInt(); + if (currentWidth.count() <= i) + currentWidth.append(lel.attribute("currentWidth").toInt()); + else + currentWidth[i] = lel.attribute("currentWidth").toInt(); + if (index.count() <= i) + index.append(lel.attribute("index").toInt()); + else + index[i] = lel.attribute("index").toInt(); + } + + setModified(false); + + return (true); +} + +bool +ProcessList::save(QDomDocument& doc, QDomElement& display) +{ + for (int i = 0; i < columns(); ++i) + { + QDomElement col = doc.createElement("column"); + display.appendChild(col); + col.setAttribute("currentWidth", columnWidth(i)); + col.setAttribute("savedWidth", savedWidth[i]); + col.setAttribute("index", header()->mapToIndex(i)); + } + + setModified(false); + + return (true); +} + +void +ProcessList::sortingChanged(int col) +{ + if (col == sortColumn) + increasing = !increasing; + else + { + sortColumn = col; + increasing = true; + } + setSorting(sortColumn, increasing); + setModified(true); +} + +int ProcessList::columnType( uint pos ) const +{ + if ( pos >= mColumnTypes.count() ) + return 0; + + if ( mColumnTypes[ pos ] == "d" || mColumnTypes[ pos ] == "D" ) + return Int; + else if ( mColumnTypes[ pos ] == "f" || mColumnTypes[ pos ] == "F" ) + return Float; + else if ( mColumnTypes[ pos ] == "t" ) + return Time; + else + return Text; +} + +bool +ProcessList::matchesFilter(KSGRD::SensorPSLine* p) const +{ + // This mechanism is likely to change in the future! + + switch (filterMode) + { + case FILTER_ALL: + return (true); + + case FILTER_SYSTEM: + return (p->uid() < 100 ? true : false); + + case FILTER_USER: + return (p->uid() >= 100 ? true : false); + + case FILTER_OWN: + default: + return (p->uid() == (long) getuid() ? true : false); + } +} + +void +ProcessList::buildList() +{ + /* Get the first process in the list, check whether it matches the + * filter and append it to QListView widget if so. */ + while (!pl.isEmpty()) + { + KSGRD::SensorPSLine* p = pl.first(); + + if (matchesFilter(p)) + { + ProcessLVI* pli = new ProcessLVI(this); + + addProcess(p, pli); + + if (selectedPIds.findIndex(p->pid()) != -1) + pli->setSelected(true); + } + pl.removeFirst(); + } +} + +void +ProcessList::buildTree() +{ + // remove all leaves that do not match the filter + deleteLeaves(); + + KSGRD::SensorPSLine* ps = pl.first(); + + while (ps) + { + if (ps->pid() == INIT_PID) + { + // insert root item into the tree widget + ProcessLVI* pli = new ProcessLVI(this); + addProcess(ps, pli); + + // remove the process from the process list, ps is now invalid + int pid = ps->pid(); + pl.remove(); + + if (selectedPIds.findIndex(pid) != -1) + pli->setSelected(true); + + // insert all child processes of current process + extendTree(&pl, pli, pid); + break; + } + else + ps = pl.next(); + } +} + +void +ProcessList::deleteLeaves(void) +{ + for ( ; ; ) + { + unsigned int i; + for (i = 0; i < pl.count() && + (!isLeafProcess(pl.at(i)->pid()) || + matchesFilter(pl.at(i))); i++) + ; + if (i == pl.count()) + return; + + pl.remove(i); + } +} + +bool +ProcessList::isLeafProcess(int pid) +{ + for (unsigned int i = 0; i < pl.count(); i++) + if (pl.at(i)->ppid() == pid) + return (false); + + return (true); +} + +void +ProcessList::extendTree(QPtrList<KSGRD::SensorPSLine>* pl, ProcessLVI* parent, int ppid) +{ + KSGRD::SensorPSLine* ps; + + // start at top list + ps = pl->first(); + + while (ps) + { + // look for a child process of the current parent + if (ps->ppid() == ppid) + { + ProcessLVI* pli = new ProcessLVI(parent); + + addProcess(ps, pli); + + if (selectedPIds.findIndex(ps->pid()) != -1) + pli->setSelected(true); + + if (ps->ppid() != INIT_PID && closedSubTrees.findIndex(ps->ppid()) != -1) + parent->setOpen(false); + else + parent->setOpen(true); + + // remove the process from the process list, ps is now invalid + int pid = ps->pid(); + pl->remove(); + + // now look for the childs of the inserted process + extendTree(pl, pli, pid); + + /* Since buildTree can remove processes from the list we + * can't find a "current" process. So we start searching + * at the top again. It's no endless loops since this + * branch is only entered when there are children of the + * current parent in the list. When we have removed them + * all the while loop will exit. */ + ps = pl->first(); + } + else + ps = pl->next(); + } +} +void +ProcessList::addProcess(KSGRD::SensorPSLine* p, ProcessLVI* pli) +{ + QString name = p->name(); + if (aliases[name]) + name = *aliases[name]; + + /* Get icon from icon list that might be appropriate for a process + * with this name. */ + QPixmap pix; + if (!iconCache[name]) + { + pix = KGlobal::iconLoader()->loadIcon(name, KIcon::Small, + KIcon::SizeSmall, KIcon::DefaultState, + 0L, true); + if (pix.isNull() || !pix.mask()) + pix = KGlobal::iconLoader()->loadIcon("unknownapp", KIcon::User, + KIcon::SizeSmall); + + if (pix.width() != 16 || pix.height() != 16) + { + /* I guess this isn't needed too often. The KIconLoader should + * scale the pixmaps already appropriately. Since I got a bug + * report claiming that it doesn't work with GNOME apps I've + * added this safeguard. */ + QImage img; + img = pix; + img.smoothScale(16, 16); + pix = img; + } + /* We copy the icon into a 24x16 pixmap to add a 4 pixel margin on + * the left and right side. In tree view mode we use the original + * icon. */ + QPixmap icon(24, 16, pix.depth()); + if (!treeViewEnabled) + { + icon.fill(); + bitBlt(&icon, 4, 0, &pix, 0, 0, pix.width(), pix.height()); + QBitmap mask(24, 16, true); + bitBlt(&mask, 4, 0, pix.mask(), 0, 0, pix.width(), pix.height()); + icon.setMask(mask); + pix = icon; + } + iconCache.insert(name, new QPixmap(pix)); + } + else + pix = *(iconCache[name]); + + // icon + process name + pli->setPixmap(0, pix); + pli->setText(0, p->name()); + + // insert remaining field into table + for (unsigned int col = 1; col < p->count(); col++) + { + if (mColumnTypes[col] == "S" && columnDict[(*p)[col]]) + pli->setText(col, *columnDict[(*p)[col]]); + else if ( mColumnTypes[col] == "f" ) + pli->setText( col, KGlobal::locale()->formatNumber( (*p)[col].toFloat() ) ); + else if ( mColumnTypes[col] == "D" ) + pli->setText( col, KGlobal::locale()->formatNumber( (*p)[col].toInt(), 0 ) ); + else + pli->setText(col, (*p)[col]); + } +} + +void +ProcessList::updateMetaInfo(void) +{ + selectedPIds.clear(); + closedSubTrees.clear(); + + QListViewItemIterator it(this); + + // iterate through all items of the listview + for ( ; it.current(); ++it ) + { + if (it.current()->isSelected() && it.current()->isVisible()) + selectedPIds.append(it.current()->text(1).toInt()); + if (treeViewEnabled && !it.current()->isOpen()) + closedSubTrees.append(it.current()->text(1).toInt()); + } + + /* In list view mode all list items are set to closed by QListView. + * If the tree view is now selected, all item will be closed. This is + * annoying. So we use the openAll flag to force all trees to open when + * the treeViewEnbled flag was set to true. */ + if (openAll) + { + if (treeViewEnabled) + closedSubTrees.clear(); + openAll = false; + } +} + +void +ProcessList::removeColumns(void) +{ + for (int i = columns() - 1; i >= 0; --i) + removeColumn(i); +} + +void +ProcessList::addColumn(const QString& label, const QString& type) +{ + QListView::addColumn(label); + uint col = columns() - 1; + if (type == "s" || type == "S") + setColumnAlignment(col, AlignLeft); + else if (type == "d" || type == "D") + setColumnAlignment(col, AlignRight); + else if (type == "t") + setColumnAlignment(col, AlignRight); + else if (type == "f") + setColumnAlignment(col, AlignRight); + else + { + kdDebug(1215) << "Unknown type " << type << " of column " << label + << " in ProcessList!" << endl; + return; + } + + mColumnTypes.append(type); + + /* Just use some sensible default values as initial setting. */ + QFontMetrics fm = fontMetrics(); + setColumnWidth(col, fm.width(label) + 10); + + if (currentWidth.count() - 1 == col) + { + /* Table has been loaded from file. We can restore the settings + * when the last column has been added. */ + for (uint i = 0; i < col; ++i) + { + /* In case the language has been changed the column width + * might need to be increased. */ + if (currentWidth[i] == 0) + { + if (fm.width(header()->label(i)) + 10 > savedWidth[i]) + savedWidth[i] = fm.width(header()->label(i)) + 10; + setColumnWidth(i, 0); + } + else + { + if (fm.width(header()->label(i)) + 10 > currentWidth[i]) + setColumnWidth(i, fm.width(header()->label(i)) + 10); + else + setColumnWidth(i, currentWidth[i]); + } + setColumnWidthMode(i, currentWidth[i] == 0 ? + QListView::Manual : QListView::Maximum); + header()->moveSection(i, index[i]); + } + setSorting(sortColumn, increasing); + } +} + +void +ProcessList::handleRMBPressed(QListViewItem* lvi, const QPoint& p, int col) +{ + if (!lvi) + return; + + lvi->setSelected( true ); + + /* lvi is only valid until the next time we hit the main event + * loop. So we need to save the information we need after calling + * processPM->exec(). */ + int currentPId = lvi->text(1).toInt(); + + int currentNiceValue = 0; + for (int i = 0; i < columns(); ++i) + if (QString::compare(header()->label(i), i18n("Nice")) == 0) + currentNiceValue = lvi->text(i).toInt(); + + QPopupMenu processPM; + if (columnWidth(col) != 0) + processPM.insertItem(i18n("Hide Column"), 5); + QPopupMenu* hiddenPM = new QPopupMenu(&processPM); + for (int i = 0; i < columns(); ++i) + if (columnWidth(i) == 0) + hiddenPM->insertItem(header()->label(i), i + 100); + if(columns()) + processPM.insertItem(i18n("Show Column"), hiddenPM); + + processPM.insertSeparator(); + + processPM.insertItem(i18n("Select All Processes"), 1); + processPM.insertItem(i18n("Unselect All Processes"), 2); + + QPopupMenu* signalPM = new QPopupMenu(&processPM); + if (killSupported && lvi->isSelected()) + { + processPM.insertSeparator(); + processPM.insertItem(i18n("Select All Child Processes"), 3); + processPM.insertItem(i18n("Unselect All Child Processes"), 4); + + signalPM->insertItem(i18n("SIGABRT"), MENU_ID_SIGABRT); + signalPM->insertItem(i18n("SIGALRM"), MENU_ID_SIGALRM); + signalPM->insertItem(i18n("SIGCHLD"), MENU_ID_SIGCHLD); + signalPM->insertItem(i18n("SIGCONT"), MENU_ID_SIGCONT); + signalPM->insertItem(i18n("SIGFPE"), MENU_ID_SIGFPE); + signalPM->insertItem(i18n("SIGHUP"), MENU_ID_SIGHUP); + signalPM->insertItem(i18n("SIGILL"), MENU_ID_SIGILL); + signalPM->insertItem(i18n("SIGINT"), MENU_ID_SIGINT); + signalPM->insertItem(i18n("SIGKILL"), MENU_ID_SIGKILL); + signalPM->insertItem(i18n("SIGPIPE"), MENU_ID_SIGPIPE); + signalPM->insertItem(i18n("SIGQUIT"), MENU_ID_SIGQUIT); + signalPM->insertItem(i18n("SIGSEGV"), MENU_ID_SIGSEGV); + signalPM->insertItem(i18n("SIGSTOP"), MENU_ID_SIGSTOP); + signalPM->insertItem(i18n("SIGTERM"), MENU_ID_SIGTERM); + signalPM->insertItem(i18n("SIGTSTP"), MENU_ID_SIGTSTP); + signalPM->insertItem(i18n("SIGTTIN"), MENU_ID_SIGTTIN); + signalPM->insertItem(i18n("SIGTTOU"), MENU_ID_SIGTTOU); + signalPM->insertItem(i18n("SIGUSR1"), MENU_ID_SIGUSR1); + signalPM->insertItem(i18n("SIGUSR2"), MENU_ID_SIGUSR2); + + processPM.insertSeparator(); + processPM.insertItem(i18n("Send Signal"), signalPM); + } + + /* differ between killSupported and reniceSupported in a future + * version. */ + if (killSupported && lvi->isSelected()) + { + processPM.insertSeparator(); + processPM.insertItem(i18n("Renice Process..."), 300); + } + + int id; + switch (id = processPM.exec(p)) + { + case -1: + break; + case 1: + case 2: + selectAllItems(id & 1); + break; + case 3: + case 4: + selectAllChilds(currentPId, id & 1); + break; + case 5: + setColumnWidthMode(col, QListView::Manual); + savedWidth[col] = columnWidth(col); + setColumnWidth(col, 0); + setModified(true); + break; + case 300: + { + ReniceDlg reniceDlg(this, "reniceDlg", currentNiceValue, currentPId); + + int reniceVal; + if ((reniceVal = reniceDlg.exec()) != 40) { + emit reniceProcess(selectedPIds, reniceVal); + } + } + break; + default: + /* IDs < 100 are used for signals. */ + if (id < 100) + { + /* we go through list to get all task also + when update interval is paused */ + selectedPIds.clear(); + QListViewItemIterator it(this, QListViewItemIterator::Visible | QListViewItemIterator::Selected); + + // iterate through all selected visible items of the listview + for ( ; it.current(); ++it ) + { + selectedPIds.append(it.current()->text(1).toInt()); + } + + QString msg = i18n("Do you really want to send signal %1 to the selected process?", + "Do you really want to send signal %1 to the %n selected processes?", + selectedPIds.count()) + .arg(signalPM->text(id)); + int answ; + switch(answ = KMessageBox::questionYesNo(this, msg, QString::null, i18n("Send"), KStdGuiItem::cancel())) + { + case KMessageBox::Yes: + { + QValueList<int>::Iterator it; + for (it = selectedPIds.begin(); it != selectedPIds.end(); ++it) + emit (killProcess(*it, id)); + break; + } + default: + break; + } + } + else + { + /* IDs >= 100 are used for hidden columns. */ + int col = id - 100; + setColumnWidthMode(col, QListView::Maximum); + setColumnWidth(col, savedWidth[col]); + setModified(true); + } + } +} + +void +ProcessList::selectAllItems(bool select) +{ + selectedPIds.clear(); + + QListViewItemIterator it(this, QListViewItemIterator::Visible); + + // iterate through all items of the listview + for ( ; it.current(); ++it ) + { + it.current()->setSelected(select); + repaintItem(it.current()); + if (select) + selectedPIds.append(it.current()->text(1).toInt()); + } +} + +void +ProcessList::selectAllChilds(int pid, bool select) +{ + QListViewItemIterator it(this, QListViewItemIterator::Visible ); + + // iterate through all items of the listview + for ( ; it.current(); ++it ) + { + // Check if PPID matches the pid (current is a child of pid) + if (it.current()->text(2).toInt() == pid) + { + int currPId = it.current()->text(1).toInt(); + it.current()->setSelected(select); + repaintItem(it.current()); + if (select) + selectedPIds.append(currPId); + else + selectedPIds.remove(currPId); + selectAllChilds(currPId, select); + } + } +} + +#include "ProcessList.moc" diff --git a/ksysguard/gui/SensorDisplayLib/ProcessList.h b/ksysguard/gui/SensorDisplayLib/ProcessList.h new file mode 100644 index 000000000..b3f484484 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ProcessList.h @@ -0,0 +1,270 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me + first. Thanks! + + */ + +#ifndef _ProcessList_h_ +#define _ProcessList_h_ + +#include <qdict.h> +#include <qdom.h> +#include <qstringlist.h> +#include <qvaluelist.h> +#include <qwidget.h> + +#include <kiconloader.h> +#include <klistview.h> + +#include "SensorClient.h" + +typedef const char* (*KeyFunc)(const char*); + +/** + * To support bi-directional sorting, and sorting of text, integers etc. we + * need a specialized version of QListViewItem. + */ +class ProcessLVI : public KListViewItem +{ +public: + ProcessLVI(QListView* lv) : KListViewItem(lv) { } + ProcessLVI(QListViewItem* lvi) : KListViewItem(lvi) { } + + virtual int compare( QListViewItem *item, int column, bool ) const; +}; + +class QPopupMenu; + +/** + * This class implementes a table filled with information about the running + * processes. The table is derived from QListView. + */ +class ProcessList : public KListView +{ + Q_OBJECT + +public: + // possible values for the filter mode + enum + { + FILTER_ALL = 0, + FILTER_SYSTEM, + FILTER_USER, + FILTER_OWN + }; + + enum ColumnType { Text, Int, Float, Time }; + + /// The constructor. + ProcessList(QWidget* parent = 0, const char* name = 0); + + /// The destructor. + ~ProcessList(); + + void removeColumns(); + + void addColumn(const QString& header, const QString& type); + + void setSortColumn(uint col, bool inc) + { + sortColumn = col; + increasing = inc; + setSorting(col, inc); + } + + uint getSortColumn() const + { + return sortColumn; + } + + bool getIncreasing() const + { + return increasing; + } + + const QValueList<int>& getSelectedPIds(); + const QStringList& getSelectedAsStrings(); + + /** + * The udpate function can be used to update the displayed process + * list. A current list of processes is requested from the OS. In + * case the list contains invalid or corrupted info, FALSE is + * returned. + */ + bool update(const QString& list); + + int columnType( uint col ) const; + + void setSensorOk(bool ok); + + void setKillSupported(bool supported) + { + killSupported = supported; + } + + bool load(QDomElement& el); + bool save(QDomDocument& doc, QDomElement& display); + +public slots: + void setTreeView(bool tv); + + /** + * This slot allows the filter mode to be set by other + * widgets. Possible values are FILTER_ALL, FILTER_SYSTEM, + * FILTER_USER and FILTER_OWN. This filter mechanism will be much + * more sophisticated in the future. + */ + void setFilterMode(int fm) + { + filterMode = fm; + setModified(true); + } + + void sortingChanged(int col); + + void handleRMBPressed(QListViewItem* lvi, const QPoint& p, int col); + + void sizeChanged(int, int, int) + { + setModified(true); + } + + void indexChanged(int, int, int) + { + setModified(true); + } + + virtual void setModified(bool mfd) + { + if (mfd != modified) + { + modified = mfd; + emit listModified(modified); + } + } + +signals: + // This signal is emitted when process pid should receive signal sig. + void killProcess(int pid, int sig); + + // This signal is emitted when process pid should be reniced. + void reniceProcess(const QValueList<int> &pids, int niceValue); + + void listModified(bool); + +private: + // items of table header RMB popup menu + enum + { + HEADER_REMOVE = 0, + HEADER_ADD, + HEADER_HELP + }; + + /** + * This function updates the lists of selected PID und the closed + * sub trees. + */ + void updateMetaInfo(void); + + /** + * This function determines whether a process matches the current + * filter mode or not. If it machtes the criteria it returns true, + * false otherwise. + */ + bool matchesFilter(KSGRD::SensorPSLine* p) const; + + /** + * This function constructs the list of processes for list + * mode. It's a straightforward appending operation to the + * QListView widget. + */ + void buildList(); + + /** + * This function constructs the tree of processes for tree mode. It + * filters out leaf-sub-trees that contain no processes that match + * the filter criteria. + */ + void buildTree(); + + /** + * This function deletes the leaf-sub-trees that do not match the + * filter criteria. + */ + void deleteLeaves(void); + + /** + * This function returns true if the process is a leaf process with + * respect to the other processes in the process list. It does not + * have to be a leaf process in the overall list of processes. + */ + bool isLeafProcess(int pid); + + /** + * This function is used to recursively construct the tree by + * removing processes from the process list an inserting them into + * the tree. + */ + void extendTree(QPtrList<KSGRD::SensorPSLine>* pl, ProcessLVI* parent, int ppid); + + /** + * This function adds a process to the list/tree. + */ + void addProcess(KSGRD::SensorPSLine* p, ProcessLVI* pli); + +private: + void selectAllItems(bool select); + void selectAllChilds(int pid, bool select); + + bool modified; + int filterMode; + int sortColumn; + bool increasing; + int refreshRate; + int currColumn; + bool killSupported; + bool treeViewEnabled; + bool openAll; + + /* The following lists are primarily used to store table specs between + * load() and the actual table creation in addColumn(). */ + QValueList<int> savedWidth; + QValueList<int> currentWidth; + QValueList<int> index; + + QPtrList<KSGRD::SensorPSLine> pl; + + QStringList mColumnTypes; + QDict<QString> columnDict; + + QValueList<int> selectedPIds; + QValueList<int> closedSubTrees; + QStringList selectedAsStrings; + + static QDict<QString> aliases; + + QDict<QPixmap> iconCache; + + QPopupMenu* headerPM; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/ReniceDlg.cc b/ksysguard/gui/SensorDisplayLib/ReniceDlg.cc new file mode 100644 index 000000000..39c05eecf --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ReniceDlg.cc @@ -0,0 +1,66 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#include <klocale.h> +#include <knuminput.h> + +#include "ReniceDlg.moc" + +ReniceDlg::ReniceDlg(QWidget* parent, const char* name, int currentPPrio, + int pid) + : KDialogBase( parent, name, true, i18n("Renice Process"), + KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true ) +{ + QWidget *page = new QWidget( this ); + setMainWidget(page); + vLay = new QVBoxLayout(page, 20, -1, "ReniceLayout"); + + QString msg; + msg = i18n("You are about to change the scheduling priority of\n" + "process %1. Be aware that only the Superuser (root)\n" + "can decrease the nice level of a process. The lower\n" + "the number is the higher the priority.\n\n" + "Please enter the desired nice level:").arg(pid); + message = new QLabel(msg, page); + message->setMinimumSize(message->sizeHint()); + vLay->addWidget(message); + + /* + * Create a slider with an LCD display to the right using a horizontal + * layout. The slider and the LCD are kept in sync through signals + */ + input = new KIntNumInput(currentPPrio, page, 10); + input->setRange(-20, 19); + vLay->addWidget(input); +} + +void ReniceDlg::slotOk() +{ + done(input->value()); +} + +void ReniceDlg::slotCancel() +{ + done(40); +} diff --git a/ksysguard/gui/SensorDisplayLib/ReniceDlg.h b/ksysguard/gui/SensorDisplayLib/ReniceDlg.h new file mode 100644 index 000000000..d8f0d2685 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/ReniceDlg.h @@ -0,0 +1,61 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef _ReniceDlg_h_ +#define _ReniceDlg_h_ + +#include <kdialogbase.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlcdnumber.h> +#include <qpushbutton.h> +#include <qslider.h> + +class KIntNumInput; + +/** + * This class creates and handles a simple dialog to change the scheduling + * priority of a process. + */ +class ReniceDlg : public KDialogBase +{ + Q_OBJECT + +public: + ReniceDlg(QWidget* parent, const char* name, int currentPPrio, int pid); + +public slots: + void slotOk(); + void slotCancel(); + +private: + QBoxLayout* vLay; + QBoxLayout* butLay; + QBoxLayout* sldLay; + + QLabel* message; + KIntNumInput* input; +}; + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/SensorDisplay.cc b/ksysguard/gui/SensorDisplayLib/SensorDisplay.cc new file mode 100644 index 000000000..805c9a492 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorDisplay.cc @@ -0,0 +1,611 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <qcheckbox.h> +#include <qdom.h> +#include <qpopupmenu.h> +#include <qspinbox.h> +#include <qwhatsthis.h> +#include <qbitmap.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <krun.h> +#include <kservice.h> + +#include "SensorManager.h" +#include "TimerSettings.h" + +#include "SensorDisplay.h" + +using namespace KSGRD; + +SensorDisplay::SensorDisplay( QWidget *parent, const char *name, + const QString &title, bool nf, bool isApplet) + : QWidget( parent, name ) +{ + mIsApplet = isApplet; + mSensors.setAutoDelete( true ); + + // default interval is 2 seconds. + mUpdateInterval = 2; + mUseGlobalUpdateInterval = true; + mModified = false; + mShowUnit = false; + mTimerId = NONE; + mFrame = 0; + mErrorIndicator = 0; + mPlotterWdg = 0; + + setTimerOn( true ); + QWhatsThis::add( this, "dummy" ); + + if(!nf) { + mFrame = new QGroupBox( 2, Qt::Vertical, "", this, "displayFrame"); + mFrame->setFlat(true); + mFrame->setAlignment(Qt::AlignHCenter); + mFrame->setInsideMargin(2); + + setTitle( title ); + /* All RMB clicks to the box frame will be handled by + * SensorDisplay::eventFilter. */ + mFrame->installEventFilter( this ); + } + + + setMinimumSize( 16, 16 ); + setModified( false ); + setSensorOk( false ); + + /* Let's call updateWhatsThis() in case the derived class does not do + * this. */ + updateWhatsThis(); +} + +SensorDisplay::~SensorDisplay() +{ + if ( SensorMgr != 0 ) + SensorMgr->disconnectClient( this ); + + killTimer( mTimerId ); +} + +void SensorDisplay::registerSensor( SensorProperties *sp ) +{ + /* Make sure that we have a connection established to the specified + * host. When a work sheet has been saved while it had dangling + * sensors, the connect info is not saved in the work sheet. In such + * a case the user can re-enter the connect information and the + * connection will be established. */ + if ( !SensorMgr->engageHost( sp->hostName() ) ) { + QString msg = i18n( "It is impossible to connect to \'%1\'." ).arg( sp->hostName() ); + KMessageBox::error( this, msg ); + } + + mSensors.append( sp ); +} + +void SensorDisplay::unregisterSensor( uint pos ) +{ + mSensors.remove( pos ); +} + +void SensorDisplay::configureUpdateInterval() +{ + TimerSettings dlg( this ); + + dlg.setUseGlobalUpdate( mUseGlobalUpdateInterval ); + dlg.setInterval( mUpdateInterval ); + + if ( dlg.exec() ) { + if ( dlg.useGlobalUpdate() ) { + mUseGlobalUpdateInterval = true; + + SensorBoard* sb = dynamic_cast<SensorBoard*>( parentWidget() ); + if ( !sb ) { + kdDebug(1215) << "dynamic cast lacks" << endl; + setUpdateInterval( 2 ); + } else { + setUpdateInterval( sb->updateInterval() ); + } + } else { + mUseGlobalUpdateInterval = false; + setUpdateInterval( dlg.interval() ); + } + + setModified( true ); + } +} + +void SensorDisplay::timerEvent( QTimerEvent* ) +{ + int i = 0; + for ( SensorProperties *s = mSensors.first(); s; s = mSensors.next(), ++i ) + sendRequest( s->hostName(), s->name(), i ); +} + +void SensorDisplay::resizeEvent( QResizeEvent* ) +{ + if(mFrame) + mFrame->setGeometry( rect() ); +} + +bool SensorDisplay::eventFilter( QObject *object, QEvent *event ) +{ + if ( event->type() == QEvent::MouseButtonPress && + ( (QMouseEvent*)event)->button() == RightButton ) { + QPopupMenu pm; + if ( mIsApplet ) { + pm.insertItem( i18n( "Launch &System Guard"), 1 ); + pm.insertSeparator(); + } + if ( hasSettingsDialog() ) + pm.insertItem( i18n( "&Properties" ), 2 ); + pm.insertItem( i18n( "&Remove Display" ), 3 ); + pm.insertSeparator(); + pm.insertItem( i18n( "&Setup Update Interval..." ), 4 ); + if ( !timerOn() ) + pm.insertItem( i18n( "&Continue Update" ), 5 ); + else + pm.insertItem( i18n( "P&ause Update" ), 6 ); + + switch ( pm.exec( QCursor::pos() ) ) { + case 1: + KRun::run(*KService::serviceByDesktopName("ksysguard"), KURL::List()); + break; + case 2: + configureSettings(); + break; + case 3: { + QCustomEvent *e = new QCustomEvent( QEvent::User ); + e->setData( this ); + kapp->postEvent( parent(), e ); + } + break; + case 4: + configureUpdateInterval(); + break; + case 5: + setTimerOn( true ); + setModified( true ); + break; + case 6: + setTimerOn( false ); + setModified( true ); + break; + } + + return true; + } else if ( event->type() == QEvent::MouseButtonRelease && + ( ( QMouseEvent*)event)->button() == LeftButton ) { + setFocus(); + } + + return QWidget::eventFilter( object, event ); +} + +void SensorDisplay::sendRequest( const QString &hostName, + const QString &command, int id ) +{ + if ( !SensorMgr->sendRequest( hostName, command, (SensorClient*)this, id ) ) + sensorError( id, true ); +} + +void SensorDisplay::sensorError( int sensorId, bool err ) +{ + if ( sensorId >= (int)mSensors.count() || sensorId < 0 ) + return; + + if ( err == mSensors.at( sensorId )->isOk() ) { + // this happens only when the sensorOk status needs to be changed. + mSensors.at( sensorId )->setIsOk( !err ); + } + + bool ok = true; + for ( uint i = 0; i < mSensors.count(); ++i ) + if ( !mSensors.at( i )->isOk() ) { + ok = false; + break; + } + + setSensorOk( ok ); +} + +void SensorDisplay::updateWhatsThis() +{ + QWhatsThis::add( this, i18n( + "<qt><p>This is a sensor display. To customize a sensor display click " + "and hold the right mouse button on either the frame or the " + "display box and select the <i>Properties</i> entry from the popup " + "menu. Select <i>Remove</i> to delete the display from the worksheet." + "</p>%1</qt>" ).arg( additionalWhatsThis() ) ); +} + +void SensorDisplay::hosts( QStringList& list ) +{ + for ( SensorProperties *s = mSensors.first(); s; s = mSensors.next() ) + if ( !list.contains( s->hostName() ) ) + list.append( s->hostName() ); +} + +QColor SensorDisplay::restoreColor( QDomElement &element, const QString &attr, + const QColor& fallback ) +{ + bool ok; + uint c = element.attribute( attr ).toUInt( &ok ); + if ( !ok ) + return fallback; + else + return QColor( (c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF ); +} + +void SensorDisplay::saveColor( QDomElement &element, const QString &attr, + const QColor &color ) +{ + int r, g, b; + color.rgb( &r, &g, &b ); + element.setAttribute( attr, (r << 16) | (g << 8) | b ); +} + +bool SensorDisplay::addSensor( const QString &hostName, const QString &name, + const QString &type, const QString &description ) +{ + registerSensor( new SensorProperties( hostName, name, type, description ) ); + return true; +} + +bool SensorDisplay::removeSensor( uint pos ) +{ + unregisterSensor( pos ); + return true; +} + +void SensorDisplay::setUpdateInterval( uint interval ) +{ + bool timerActive = timerOn(); + + if ( timerActive ) + setTimerOn( false ); + + mUpdateInterval = interval; + + if ( timerActive ) + setTimerOn( true ); +} + +bool SensorDisplay::hasSettingsDialog() const +{ + return false; +} + +void SensorDisplay::configureSettings() +{ +} + +void SensorDisplay::setUseGlobalUpdateInterval( bool value ) +{ + mUseGlobalUpdateInterval = value; +} + +bool SensorDisplay::useGlobalUpdateInterval() const +{ + return mUseGlobalUpdateInterval; +} + +QString SensorDisplay::additionalWhatsThis() +{ + return QString::null; +} + +void SensorDisplay::sensorLost( int reqId ) +{ + sensorError( reqId, true ); +} + +bool SensorDisplay::restoreSettings( QDomElement &element ) +{ + QString str = element.attribute( "showUnit", "X" ); + if(!str.isEmpty() && str != "X") { + mShowUnit = str.toInt(); + } + str = element.attribute( "unit", QString::null ); + if(!str.isEmpty()) + setUnit(str); + str = element.attribute( "title", QString::null ); + if(!str.isEmpty()) + setTitle(str); + + if ( element.attribute( "updateInterval" ) != QString::null ) { + mUseGlobalUpdateInterval = false; + setUpdateInterval( element.attribute( "updateInterval", "2" ).toInt() ); + } else { + mUseGlobalUpdateInterval = true; + + SensorBoard* sb = dynamic_cast<SensorBoard*>( parentWidget() ); + if ( !sb ) { + kdDebug(1215) << "dynamic cast lacks" << endl; + setUpdateInterval( 2 ); + } else + setUpdateInterval( sb->updateInterval() ); + } + + if ( element.attribute( "pause", "0" ).toInt() == 0 ) + setTimerOn( true ); + else + setTimerOn( false ); + + return true; +} + +bool SensorDisplay::saveSettings( QDomDocument&, QDomElement &element, bool ) +{ + element.setAttribute( "title", title() ); + element.setAttribute( "unit", unit() ); + element.setAttribute( "showUnit", mShowUnit ); + + if ( mUseGlobalUpdateInterval ) + element.setAttribute( "globalUpdate", "1" ); + else { + element.setAttribute( "globalUpdate", "0" ); + element.setAttribute( "updateInterval", mUpdateInterval ); + } + + if ( !timerOn() ) + element.setAttribute( "pause", 1 ); + else + element.setAttribute( "pause", 0 ); + + return true; +} + +void SensorDisplay::setTimerOn( bool on ) +{ + if ( on ) { + if ( mTimerId == NONE ) + mTimerId = startTimer( mUpdateInterval * 1000 ); + } else { + if ( mTimerId != NONE ) { + killTimer( mTimerId ); + mTimerId = NONE; + } + } +} + +bool SensorDisplay::timerOn() const +{ + return ( mTimerId != NONE ); +} + +bool SensorDisplay::modified() const +{ + return mModified; +} + +QPtrList<SensorProperties> &SensorDisplay::sensors() +{ + return mSensors; +} + +void SensorDisplay::rmbPressed() +{ + emit showPopupMenu( this ); +} + +void SensorDisplay::applySettings() +{ +} + +void SensorDisplay::applyStyle() +{ +} + +void SensorDisplay::setModified( bool value ) +{ + if ( value != mModified ) { + mModified = value; + emit modified( mModified ); + } +} + +void SensorDisplay::setSensorOk( bool ok ) +{ + if ( ok ) { + delete mErrorIndicator; + mErrorIndicator = 0; + } else { + if ( mErrorIndicator ) + return; + + QPixmap errorIcon = KGlobal::iconLoader()->loadIcon( "connect_creating", KIcon::Desktop, + KIcon::SizeSmall ); + if ( !mPlotterWdg ) + return; + + mErrorIndicator = new QWidget( mPlotterWdg ); + mErrorIndicator->setErasePixmap( errorIcon ); + mErrorIndicator->resize( errorIcon.size() ); + if ( errorIcon.mask() ) + mErrorIndicator->setMask( *errorIcon.mask() ); + mErrorIndicator->move( 0, 0 ); + mErrorIndicator->show(); + } +} + +void SensorDisplay::setTitle( const QString &title ) +{ + mTitle = title; + + if(!mFrame) { + return; //fixme. create a frame and move widget inside it. + } + + /* Changing the frame title may increase the width of the frame and + * hence breaks the layout. To avoid this, we save the original size + * and restore it after we have set the frame title. */ + QSize s = mFrame->size(); + + if ( mShowUnit && !mUnit.isEmpty() ) + mFrame->setTitle( mTitle + " [" + mUnit + "]" ); + else + mFrame->setTitle( mTitle ); + mFrame->setGeometry( 0, 0, s.width(), s.height() ); +} + +QString SensorDisplay::title() const +{ + return mTitle; +} + +void SensorDisplay::setUnit( const QString &unit ) +{ + mUnit = unit; +} + +QString SensorDisplay::unit() const +{ + return mUnit; +} + +void SensorDisplay::setShowUnit( bool value ) +{ + mShowUnit = value; +} + +bool SensorDisplay::showUnit() const +{ + return mShowUnit; +} + +void SensorDisplay::setPlotterWidget( QWidget *wdg ) +{ + mPlotterWdg = wdg; + +} + +QWidget *SensorDisplay::frame() +{ + return mFrame; +} + +//void SensorDisplay::setNoFrame( bool /*value*/ ) +//{ + //FIXME - delete or create the frame as needed +//} + +bool SensorDisplay::noFrame() const +{ + return !mFrame; +} + +void SensorDisplay::reorderSensors(const QValueList<int> &orderOfSensors) +{ + QPtrList<SensorProperties> newSensors; + for ( uint i = 0; i < orderOfSensors.count(); ++i ) { + newSensors.append( mSensors.at(orderOfSensors[i] )); + } + + mSensors.setAutoDelete( false ); + mSensors = newSensors; + mSensors.setAutoDelete( true ); +} + + +SensorProperties::SensorProperties() +{ +} + +SensorProperties::SensorProperties( const QString &hostName, const QString &name, + const QString &type, const QString &description ) + : mHostName( hostName ), mName( name ), mType( type ), mDescription( description ) +{ + mOk = false; +} + +SensorProperties::~SensorProperties() +{ +} + +void SensorProperties::setHostName( const QString &hostName ) +{ + mHostName = hostName; +} + +QString SensorProperties::hostName() const +{ + return mHostName; +} + +void SensorProperties::setName( const QString &name ) +{ + mName = name; +} + +QString SensorProperties::name() const +{ + return mName; +} + +void SensorProperties::setType( const QString &type ) +{ + mType = type; +} + +QString SensorProperties::type() const +{ + return mType; +} + +void SensorProperties::setDescription( const QString &description ) +{ + mDescription = description; +} + +QString SensorProperties::description() const +{ + return mDescription; +} + +void SensorProperties::setUnit( const QString &unit ) +{ + mUnit = unit; +} + +QString SensorProperties::unit() const +{ + return mUnit; +} + +void SensorProperties::setIsOk( bool value ) +{ + mOk = value; +} + +bool SensorProperties::isOk() const +{ + return mOk; +} + +#include "SensorDisplay.moc" diff --git a/ksysguard/gui/SensorDisplayLib/SensorDisplay.h b/ksysguard/gui/SensorDisplayLib/SensorDisplay.h new file mode 100644 index 000000000..e5e867a01 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorDisplay.h @@ -0,0 +1,331 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_SENSORDISPLAY_H +#define KSG_SENSORDISPLAY_H + +#include <qgroupbox.h> +#include <qlabel.h> +#include <qvaluelist.h> +#include <qwidget.h> + +#include <knotifyclient.h> + +#include <ksgrd/SensorClient.h> + +#define NONE -1 + +class QDomDocument; +class QDomElement; + +namespace KSGRD { + +class SensorProperties; + +/** + This class is the base class for all displays for sensors. A + display is any kind of widget that can display the value of one or + more sensors in any form. It must be inherited by all displays that + should be inserted into the work sheet. + */ +class SensorDisplay : public QWidget, public SensorClient +{ + Q_OBJECT + + public: + /** + Constructor. + */ + SensorDisplay( QWidget *parent = 0, const char *name = 0, + const QString& title = 0, bool nf = false, bool isApplet = false ); + + /** + Destructor. + */ + virtual ~SensorDisplay(); + + /** + Sets the title of the display. + */ + void setTitle( const QString &title ); + + /** + Returns the title of the display. + */ + QString title() const; + + /** + Sets the unit of the display. + */ + void setUnit( const QString &unit ); + + /** + Returns the unit of the display. + */ + QString unit() const; + + /** + Sets whether the unit string should be displayed at the top + of the display frame. + */ + void setShowUnit( bool value ); + + /** + Returns whether the unit string should be displayed at the top + of the display frame. @see setShowUnit() + */ + bool showUnit() const; + + /** + Sets whether the update interval of the work sheet should be + used instead of the one, set by @ref setUpdateInterval(). + */ + void setUseGlobalUpdateInterval( bool value ); + + /** + Returns whether the update interval of the work sheet should be + used instead of the one, set by @ref setUpdateInterval(). + see @ref setUseGlobalUpdateInterval() + */ + bool useGlobalUpdateInterval() const; + + /** + Sets the update interval of the timer, which triggers the timer + events. The state of the timer can be set with @ref setTimerOn(). + */ + void setUpdateInterval( uint interval ); + + /** + Returns the update interval. + */ + uint updateInterval() const; + + /** + This method appends all hosts of the display to @ref list. + */ + void hosts( QStringList& list ); + + /** + Sets the widget on which the error icon can be drawn. + */ + void setPlotterWidget( QWidget *plotter ); + + /** + Returns the widget on which the error icon can be drawn. + */ + QWidget *plotterWidget() const; + + /** + Add a sensor to the display. + + @param hostName The name of the host, the sensor belongs to. + @param name The sensor name. + @param type The type of the sensor. + @param description A short description of the sensor. + */ + virtual bool addSensor( const QString &hostName, const QString &name, + const QString &type, const QString &description ); + + /** + Removes the sensor from the display, that is at the position + @ref pos of the intern sensor list. + */ + virtual bool removeSensor( uint pos ); + + /** + This function is a wrapper function to SensorManager::sendRequest. + It should be used by all SensorDisplay functions that need to send + a request to a sensor since it performs an appropriate error + handling by removing the display of necessary. + */ + void sendRequest( const QString &hostName, const QString &cmd, int id ); + + /** + Raises the configure dialog to setup the update interval. + */ + void configureUpdateInterval(); + + /** + Returns whether the display provides a settings dialog. + This method should be reimplemented in the derived class. + */ + virtual bool hasSettingsDialog() const; + + /** + This method is called to raise the settings dialog of the + display. It should be reimplemented in the derived class. + */ + virtual void configureSettings(); + + /** + Reimplement this method to setup the display from config data. + */ + virtual bool restoreSettings( QDomElement& ); + + /** + Reimplement this method to save the displays config data. + */ + virtual bool saveSettings( QDomDocument&, QDomElement&, bool = true ); + + /** + Reimplement this method to catch error messages from the SensorManager. + + @param sensorId The unique id of the sensor. + @param mode The mode: true = error, false = everthing ok + */ + virtual void sensorError( int sensorId, bool mode ); + + /** + Normaly you shouldn't reimplement this methode + */ + virtual void sensorLost( int reqId ); + + public slots: + /** + If @ref value is true, this method starts the timer that triggers + timer events. If @ref value is false, the timer is stopped. + */ + void setTimerOn( bool value ); + + /** + Calling this method emits the @ref showPopupMenu() with this + display as argument. + */ + void rmbPressed(); + + /** + Sets whether the display is modified of not. + */ + void setModified( bool modified ); + + /** + This method can be used to apply the new settings. Just connect + the applyClicked() signal of your configuration dialog with this + slot and reimplement it. + */ + virtual void applySettings(); + + /** + This methid is called whenever the global style is changed. + Reimplement it to apply the new style settings to the display. + */ + virtual void applyStyle(); + + + signals: + void showPopupMenu( KSGRD::SensorDisplay *display ); + void modified( bool modified ); + + protected: + virtual bool eventFilter( QObject*, QEvent* ); + virtual void resizeEvent( QResizeEvent* ); + virtual void timerEvent( QTimerEvent* ); + + void registerSensor( SensorProperties *sp ); + void unregisterSensor( uint pos ); + + QColor restoreColor( QDomElement &element, const QString &attr, + const QColor& fallback ); + void saveColor( QDomElement &element, const QString &attr, + const QColor &color ); + + virtual QString additionalWhatsThis(); + + void setSensorOk( bool ok ); + + bool modified() const; + bool timerOn() const; + + QWidget *frame(); + +// void setNoFrame( bool value ); + bool noFrame() const; + + void reorderSensors(const QValueList<int> &orderOfSensors); + QPtrList<SensorProperties> &sensors(); + + private: + void updateWhatsThis(); + + bool mShowUnit; + bool mUseGlobalUpdateInterval; + bool mModified; + bool mNoFrame; + bool mIsApplet; + + int mTimerId; + int mUpdateInterval; + + // The frame around the other widgets. + QGroupBox* mFrame; + + QPtrList<SensorProperties> mSensors; + + QString mTitle; + QString mUnit; + + QWidget* mErrorIndicator; + QWidget* mPlotterWdg; +}; + +class SensorProperties +{ + public: + SensorProperties(); + SensorProperties( const QString &hostName, const QString &name, + const QString &type, const QString &description ); + ~SensorProperties(); + + void setHostName( const QString &hostName ); + QString hostName() const; + + void setName( const QString &name ); + QString name() const; + + void setType( const QString &type ); + QString type() const; + + void setDescription( const QString &description ); + QString description() const; + + void setUnit( const QString &unit ); + QString unit() const; + + void setIsOk( bool value ); + bool isOk() const; + + private: + QString mHostName; + QString mName; + QString mType; + QString mDescription; + QString mUnit; + + /* This flag indicates whether the communication to the sensor is + * ok or not. */ + bool mOk; +}; + +} + +#endif diff --git a/ksysguard/gui/SensorDisplayLib/SensorLogger.cc b/ksysguard/gui/SensorDisplayLib/SensorLogger.cc new file mode 100644 index 000000000..b51ba67e0 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLogger.cc @@ -0,0 +1,437 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <kapplication.h> +#include <kiconloader.h> +#include <klocale.h> + +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> + +#include <qfile.h> + +#include "SensorLogger.moc" +#include "SensorLoggerSettings.h" + +SLListViewItem::SLListViewItem(QListView *parent) + : QListViewItem(parent) +{ +} + +LogSensor::LogSensor(QListView *parent) + : timerID( NONE ), lowerLimitActive( 0 ), upperLimitActive( 0 ), + lowerLimit( 0 ), upperLimit( 0 ) +{ + Q_CHECK_PTR(parent); + + monitor = parent; + + lvi = new SLListViewItem(monitor); + Q_CHECK_PTR(lvi); + + pixmap_running = UserIcon( "running" ); + pixmap_waiting = UserIcon( "waiting" ); + + lvi->setPixmap(0, pixmap_waiting); + lvi->setTextColor(monitor->colorGroup().text()); + + monitor->insertItem(lvi); +} + +LogSensor::~LogSensor(void) +{ + if ((lvi) && (monitor)) + delete lvi; +} + +void +LogSensor::startLogging(void) +{ + lvi->setPixmap(0, pixmap_running); + timerOn(); +} + +void +LogSensor::stopLogging(void) +{ + lvi->setPixmap(0, pixmap_waiting); + lvi->setTextColor(monitor->colorGroup().text()); + lvi->repaint(); + timerOff(); +} + +void +LogSensor::timerEvent(QTimerEvent*) +{ + KSGRD::SensorMgr->sendRequest(hostName, sensorName, (KSGRD::SensorClient*) this, 42); +} + +void +LogSensor::answerReceived(int id, const QString& answer) +{ + QFile logFile(fileName); + + if (!logFile.open(IO_ReadWrite | IO_Append)) + { + stopLogging(); + return; + } + + switch (id) + { + case 42: { + QTextStream stream(&logFile); + double value = answer.toDouble(); + + if (lowerLimitActive && value < lowerLimit) + { + timerOff(); + lowerLimitActive = false; + lvi->setTextColor(monitor->colorGroup().foreground()); + lvi->repaint(); + KNotifyClient::event(monitor->winId(), "sensor_alarm", QString("sensor '%1' at '%2' reached lower limit").arg(sensorName).arg(hostName)); + timerOn(); + } else if (upperLimitActive && value > upperLimit) + { + timerOff(); + upperLimitActive = false; + lvi->setTextColor(monitor->colorGroup().foreground()); + lvi->repaint(); + KNotifyClient::event(monitor->winId(), "sensor_alarm", QString("sensor '%1' at '%2' reached upper limit").arg(sensorName).arg(hostName)); + timerOn(); + } + QDate date = QDateTime::currentDateTime().date(); + QTime time = QDateTime::currentDateTime().time(); + + stream << QString("%1 %2 %3 %4 %5: %6\n").arg(date.shortMonthName(date.month())).arg(date.day()).arg(time.toString()).arg(hostName).arg(sensorName).arg(value); + } + } + + logFile.close(); +} + +SensorLogger::SensorLogger(QWidget *parent, const char *name, const QString& title) + : KSGRD::SensorDisplay(parent, name, title) +{ + monitor = new QListView(this, "monitor"); + Q_CHECK_PTR(monitor); + + monitor->addColumn(i18n("Logging")); + monitor->addColumn(i18n("Timer Interval")); + monitor->addColumn(i18n("Sensor Name")); + monitor->addColumn(i18n("Host Name")); + monitor->addColumn(i18n("Log File")); + + QColorGroup cgroup = monitor->colorGroup(); + cgroup.setColor(QColorGroup::Text, KSGRD::Style->firstForegroundColor()); + cgroup.setColor(QColorGroup::Base, KSGRD::Style->backgroundColor()); + cgroup.setColor(QColorGroup::Foreground, KSGRD::Style->alarmColor()); + monitor->setPalette(QPalette(cgroup, cgroup, cgroup)); + monitor->setSelectionMode(QListView::NoSelection); + + connect(monitor, SIGNAL(rightButtonClicked(QListViewItem*, const QPoint&, int)), this, SLOT(RMBClicked(QListViewItem*, const QPoint&, int))); + + setTitle(i18n("Sensor Logger")); + + logSensors.setAutoDelete(true); + + setPlotterWidget(monitor); + + setMinimumSize(50, 25); + setModified(false); +} + +SensorLogger::~SensorLogger(void) +{ +} + +bool +SensorLogger::addSensor(const QString& hostName, const QString& sensorName, const QString& sensorType, const QString&) +{ + if (sensorType != "integer" && sensorType != "float") + return (false); + + sld = new SensorLoggerDlg(this, "SensorLoggerDlg"); + Q_CHECK_PTR(sld); + + if (sld->exec()) { + if (!sld->fileName().isEmpty()) { + LogSensor *sensor = new LogSensor(monitor); + Q_CHECK_PTR(sensor); + + sensor->setHostName(hostName); + sensor->setSensorName(sensorName); + sensor->setFileName(sld->fileName()); + sensor->setTimerInterval(sld->timerInterval()); + sensor->setLowerLimitActive(sld->lowerLimitActive()); + sensor->setUpperLimitActive(sld->upperLimitActive()); + sensor->setLowerLimit(sld->lowerLimit()); + sensor->setUpperLimit(sld->upperLimit()); + + logSensors.append(sensor); + + setModified(true); + } + } + + delete sld; + sld = 0; + + return (true); +} + +bool +SensorLogger::editSensor(LogSensor* sensor) +{ + sld = new SensorLoggerDlg(this, "SensorLoggerDlg"); + Q_CHECK_PTR(sld); + + sld->setFileName(sensor->getFileName()); + sld->setTimerInterval(sensor->getTimerInterval()); + sld->setLowerLimitActive(sensor->getLowerLimitActive()); + sld->setLowerLimit(sensor->getLowerLimit()); + sld->setUpperLimitActive(sensor->getUpperLimitActive()); + sld->setUpperLimit(sensor->getUpperLimit()); + + if (sld->exec()) { + if (!sld->fileName().isEmpty()) { + sensor->setFileName(sld->fileName()); + sensor->setTimerInterval(sld->timerInterval()); + sensor->setLowerLimitActive(sld->lowerLimitActive()); + sensor->setUpperLimitActive(sld->upperLimitActive()); + sensor->setLowerLimit(sld->lowerLimit()); + sensor->setUpperLimit(sld->upperLimit()); + + setModified(true); + } + } + + delete sld; + sld = 0; + + return (true); +} + +void +SensorLogger::configureSettings() +{ + QColorGroup cgroup = monitor->colorGroup(); + + sls = new SensorLoggerSettings(this, "SensorLoggerSettings"); + Q_CHECK_PTR(sls); + + connect( sls, SIGNAL( applyClicked() ), SLOT( applySettings() ) ); + + sls->setTitle(title()); + sls->setForegroundColor(cgroup.text()); + sls->setBackgroundColor(cgroup.base()); + sls->setAlarmColor(cgroup.foreground()); + + if (sls->exec()) + applySettings(); + + delete sls; + sls = 0; +} + +void +SensorLogger::applySettings() +{ + QColorGroup cgroup = monitor->colorGroup(); + + setTitle(sls->title()); + + cgroup.setColor(QColorGroup::Text, sls->foregroundColor()); + cgroup.setColor(QColorGroup::Base, sls->backgroundColor()); + cgroup.setColor(QColorGroup::Foreground, sls->alarmColor()); + monitor->setPalette(QPalette(cgroup, cgroup, cgroup)); + + setModified(true); +} + +void +SensorLogger::applyStyle(void) +{ + QColorGroup cgroup = monitor->colorGroup(); + + cgroup.setColor(QColorGroup::Text, KSGRD::Style->firstForegroundColor()); + cgroup.setColor(QColorGroup::Base, KSGRD::Style->backgroundColor()); + cgroup.setColor(QColorGroup::Foreground, KSGRD::Style->alarmColor()); + monitor->setPalette(QPalette(cgroup, cgroup, cgroup)); + + setModified(true); +} + +bool +SensorLogger::restoreSettings(QDomElement& element) +{ + QColorGroup cgroup = monitor->colorGroup(); + + cgroup.setColor(QColorGroup::Text, restoreColor(element, "textColor", Qt::green)); + cgroup.setColor(QColorGroup::Base, restoreColor(element, "backgroundColor", Qt::black)); + cgroup.setColor(QColorGroup::Foreground, restoreColor(element, "alarmColor", Qt::red)); + monitor->setPalette(QPalette(cgroup, cgroup, cgroup)); + + logSensors.clear(); + + QDomNodeList dnList = element.elementsByTagName("logsensors"); + for (uint i = 0; i < dnList.count(); i++) { + QDomElement element = dnList.item(i).toElement(); + LogSensor* sensor = new LogSensor(monitor); + Q_CHECK_PTR(sensor); + + sensor->setHostName(element.attribute("hostName")); + sensor->setSensorName(element.attribute("sensorName")); + sensor->setFileName(element.attribute("fileName")); + sensor->setTimerInterval(element.attribute("timerInterval").toInt()); + sensor->setLowerLimitActive(element.attribute("lowerLimitActive").toInt()); + sensor->setLowerLimit(element.attribute("lowerLimit").toDouble()); + sensor->setUpperLimitActive(element.attribute("upperLimitActive").toInt()); + sensor->setUpperLimit(element.attribute("upperLimit").toDouble()); + + logSensors.append(sensor); + } + + SensorDisplay::restoreSettings(element); + + setModified(false); + + return (true); +} + +bool +SensorLogger::saveSettings(QDomDocument& doc, QDomElement& element, bool save) +{ + saveColor(element, "textColor", monitor->colorGroup().text()); + saveColor(element, "backgroundColor", monitor->colorGroup().base()); + saveColor(element, "alarmColor", monitor->colorGroup().foreground()); + + for (LogSensor* sensor = logSensors.first(); sensor != 0; sensor = logSensors.next()) + { + QDomElement log = doc.createElement("logsensors"); + log.setAttribute("sensorName", sensor->getSensorName()); + log.setAttribute("hostName", sensor->getHostName()); + log.setAttribute("fileName", sensor->getFileName()); + log.setAttribute("timerInterval", sensor->getTimerInterval()); + log.setAttribute("lowerLimitActive", QString("%1").arg(sensor->getLowerLimitActive())); + log.setAttribute("lowerLimit", QString("%1").arg(sensor->getLowerLimit())); + log.setAttribute("upperLimitActive", QString("%1").arg(sensor->getUpperLimitActive())); + log.setAttribute("upperLimit", QString("%1").arg(sensor->getUpperLimit())); + + element.appendChild(log); + } + + SensorDisplay::saveSettings(doc, element); + + if (save) + setModified(false); + + return (true); +} + +void +SensorLogger::answerReceived(int, const QString&) +{ + // we do not use this, since all answers are received by the LogSensors +} + +void +SensorLogger::resizeEvent(QResizeEvent*) +{ + frame()->setGeometry(0, 0, this->width(), this->height()); + monitor->setGeometry(10, 20, this->width() - 20, this->height() - 30); +} + +LogSensor* +SensorLogger::getLogSensor(QListViewItem* item) +{ + for (LogSensor* sensor = logSensors.first(); sensor != 0; sensor = logSensors.next()) + { + if (item == sensor->getListViewItem()) { + return sensor; + } + } + + return NULL; +} + +void +SensorLogger::RMBClicked(QListViewItem* item, const QPoint& point, int) +{ + QPopupMenu pm; + if (hasSettingsDialog()) + pm.insertItem(i18n("&Properties"), 1); + pm.insertItem(i18n("&Remove Display"), 2); + pm.insertSeparator(-1); + pm.insertItem(i18n("&Remove Sensor"), 3); + pm.insertItem(i18n("&Edit Sensor..."), 4); + + if ( !item ) + { + pm.setItemEnabled( 3, false ); + pm.setItemEnabled( 4, false ); + } + else + { + LogSensor* sensor = getLogSensor(item); + + if ( sensor->isLogging() ) + pm.insertItem(i18n("St&op Logging"), 6); + else + pm.insertItem(i18n("S&tart Logging"), 5); + } + + switch (pm.exec(point)) + { + case 1: + configureSettings(); + break; + case 2: { + QCustomEvent* ev = new QCustomEvent(QEvent::User); + ev->setData(this); + kapp->postEvent(parent(), ev); + break; + } + case 3: { + LogSensor* sensor = getLogSensor(item); + if (sensor) + logSensors.remove(sensor); + break; + } + case 4: { + LogSensor* sensor = getLogSensor(item); + if (sensor) + editSensor(sensor); + break; + } + case 5: { + LogSensor* sensor = getLogSensor(item); + if (sensor) + sensor->startLogging(); + break; + } + case 6: { + LogSensor* sensor = getLogSensor(item); + if (sensor) + sensor->stopLogging(); + break; + } + } +} diff --git a/ksysguard/gui/SensorDisplayLib/SensorLogger.h b/ksysguard/gui/SensorDisplayLib/SensorLogger.h new file mode 100644 index 000000000..835e62401 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLogger.h @@ -0,0 +1,184 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 _SensorLogger_h +#define _SensorLogger_h + +#include <qdom.h> +#include <qlabel.h> +#include <qlineedit.h> +#include <qlistview.h> +#include <qpopupmenu.h> +#include <qspinbox.h> +#include <qstring.h> + +#include <SensorDisplay.h> + +#include "SensorLoggerDlg.h" + +#define NONE -1 + +class SensorLoggerSettings; + +class SLListViewItem : public QListViewItem +{ +public: + SLListViewItem(QListView *parent = 0); + + void setTextColor(const QColor& color) { textColor = color; } + + void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment) { + QColorGroup cgroup(cg); + cgroup.setColor(QColorGroup::Text, textColor); + QListViewItem::paintCell(p, cgroup, column, width, alignment); + + } + + void paintFocus(QPainter *, const QColorGroup, const QRect) {} + +private: + QColor textColor; +}; + +class LogSensor : public QObject, public KSGRD::SensorClient +{ + Q_OBJECT +public: + LogSensor(QListView *parent); + ~LogSensor(void); + + void answerReceived(int id, const QString& answer); + + void setHostName(const QString& name) { hostName = name; lvi->setText(3, name); } + void setSensorName(const QString& name) { sensorName = name; lvi->setText(2, name); } + void setFileName(const QString& name) + { + fileName = name; + lvi->setText(4, name); + } + void setUpperLimitActive(bool value) { upperLimitActive = value; } + void setLowerLimitActive(bool value) { lowerLimitActive = value; } + void setUpperLimit(double value) { upperLimit = value; } + void setLowerLimit(double value) { lowerLimit = value; } + + void setTimerInterval(int interval) { + timerInterval = interval; + + if (timerID != NONE) + { + timerOff(); + timerOn(); + } + + lvi->setText(1, QString("%1").arg(interval)); + } + + QString getSensorName(void) { return sensorName; } + QString getHostName(void) { return hostName; } + QString getFileName(void) { return fileName; } + int getTimerInterval(void) { return timerInterval; } + bool getUpperLimitActive(void) { return upperLimitActive; } + bool getLowerLimitActive(void) { return lowerLimitActive; } + double getUpperLimit(void) { return upperLimit; } + double getLowerLimit(void) { return lowerLimit; } + QListViewItem* getListViewItem(void) { return lvi; } + +public slots: + void timerOff() + { + killTimer(timerID); + timerID = NONE; + } + + void timerOn() + { + timerID = startTimer(timerInterval * 1000); + } + + bool isLogging() { return timerID != NONE; } + + void startLogging(void); + void stopLogging(void); + +protected: + virtual void timerEvent(QTimerEvent*); + +private: + QListView* monitor; + SLListViewItem* lvi; + QPixmap pixmap_running; + QPixmap pixmap_waiting; + QString sensorName; + QString hostName; + QString fileName; + + int timerInterval; + int timerID; + + bool lowerLimitActive; + bool upperLimitActive; + + double lowerLimit; + double upperLimit; +}; + +class SensorLogger : public KSGRD::SensorDisplay +{ + Q_OBJECT +public: + SensorLogger(QWidget *parent = 0, const char *name = 0, const QString& title = 0); + ~SensorLogger(void); + + bool addSensor(const QString& hostName, const QString& sensorName, const QString& sensorType, + const QString& sensorDescr); + + bool editSensor(LogSensor*); + + void answerReceived(int id, const QString& answer); + void resizeEvent(QResizeEvent*); + + bool restoreSettings(QDomElement& element); + bool saveSettings(QDomDocument& doc, QDomElement& element, bool save = true); + + void configureSettings(void); + + virtual bool hasSettingsDialog() const + { + return (true); + } + +public slots: + void applySettings(); + void applyStyle(); + void RMBClicked(QListViewItem*, const QPoint&, int); + +protected: + LogSensor* getLogSensor(QListViewItem*); + +private: + QListView* monitor; + + QPtrList<LogSensor> logSensors; + + SensorLoggerDlg *sld; + SensorLoggerSettings *sls; +}; + +#endif // _SensorLogger_h diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerDlg.cc b/ksysguard/gui/SensorDisplayLib/SensorLoggerDlg.cc new file mode 100644 index 000000000..f07b55ae4 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLoggerDlg.cc @@ -0,0 +1,106 @@ +/* This file is part of the KDE project + Copyright ( C ) 2003 Nadeem Hasan <nhasan@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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "SensorLoggerDlg.h" +#include "SensorLoggerDlgWidget.h" + +#include <qlayout.h> + +#include <klocale.h> + +SensorLoggerDlg::SensorLoggerDlg( QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n( "Sensor Logger" ), + Ok|Cancel, Ok, true ) +{ + QWidget *main = new QWidget( this ); + + QVBoxLayout *topLayout = new QVBoxLayout( main, 0, KDialog::spacingHint() ); + + m_loggerWidget = new SensorLoggerDlgWidget( main, "m_loggerWidget" ); + topLayout->addWidget( m_loggerWidget ); + topLayout->addStretch(); + + setMainWidget( main ); +} + +QString SensorLoggerDlg::fileName() const +{ + return m_loggerWidget->fileName(); +} + +int SensorLoggerDlg::timerInterval() const +{ + return m_loggerWidget->timerInterval(); +} + +bool SensorLoggerDlg::lowerLimitActive() const +{ + return m_loggerWidget->lowerLimitActive(); +} + +bool SensorLoggerDlg::upperLimitActive() const +{ + return m_loggerWidget->upperLimitActive(); +} + +double SensorLoggerDlg::lowerLimit() const +{ + return m_loggerWidget->lowerLimit(); +} + +double SensorLoggerDlg::upperLimit() const +{ + return m_loggerWidget->upperLimit(); +} + +void SensorLoggerDlg::setFileName( const QString &url ) +{ + m_loggerWidget->setFileName( url ); +} + +void SensorLoggerDlg::setTimerInterval( int i ) +{ + m_loggerWidget->setTimerInterval( i ); +} + +void SensorLoggerDlg::setLowerLimitActive( bool b ) +{ + m_loggerWidget->setLowerLimitActive( b ); +} + +void SensorLoggerDlg::setUpperLimitActive( bool b ) +{ + m_loggerWidget->setUpperLimitActive( b ); +} + +void SensorLoggerDlg::setLowerLimit( double limit ) +{ + m_loggerWidget->setLowerLimit( limit ); +} + +void SensorLoggerDlg::setUpperLimit( double limit ) +{ + m_loggerWidget->setUpperLimit( limit ); +} + +#include "SensorLoggerDlg.moc" + +/* vim: et sw=2 ts=2 +*/ + diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerDlg.h b/ksysguard/gui/SensorDisplayLib/SensorLoggerDlg.h new file mode 100644 index 000000000..3af8290c8 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLoggerDlg.h @@ -0,0 +1,62 @@ +/* This file is part of the KDE project + Copyright ( C ) 2003 Nadeem Hasan <nhasan@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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#ifndef SENSORLOGGERDLG_H +#define SENSORLOGGERDLG_H + +#include <kdialogbase.h> + +#include <qstring.h> +#include <qcolor.h> + +class SensorLoggerDlgWidget; + +class SensorLoggerDlg : public KDialogBase +{ + Q_OBJECT + + public: + + SensorLoggerDlg( QWidget *parent=0, const char *name=0 ); + + QString fileName() const; + int timerInterval() const; + bool lowerLimitActive() const; + bool upperLimitActive() const; + double lowerLimit() const; + double upperLimit() const; + + void setFileName( const QString & ); + void setTimerInterval( int ); + void setLowerLimitActive( bool ); + void setUpperLimitActive( bool ); + void setLowerLimit( double ); + void setUpperLimit( double ); + + private: + + SensorLoggerDlgWidget *m_loggerWidget; +}; + +#endif // SENSORLOGGERDLG_H + +/* vim: et sw=2 ts=2 +*/ + diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerDlgWidget.ui b/ksysguard/gui/SensorDisplayLib/SensorLoggerDlgWidget.ui new file mode 100644 index 000000000..26d3b2d49 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLoggerDlgWidget.ui @@ -0,0 +1,263 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>SensorLoggerDlgWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>SensorLoggerDlgWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>363</width> + <height>254</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>fileFrame</cstring> + </property> + <property name="frameShape"> + <enum>GroupBoxPanel</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="title"> + <string>File</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KURLRequester"> + <property name="name"> + <cstring>m_fileName</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>timerFrame</cstring> + </property> + <property name="title"> + <string>Timer Interval</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KIntNumInput"> + <property name="name"> + <cstring>m_timerInterval</cstring> + </property> + <property name="value"> + <number>2</number> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="maxValue"> + <number>99</number> + </property> + <property name="suffix"> + <string> sec</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>GroupBox1</cstring> + </property> + <property name="title"> + <string>Alarm for Minimum Value</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_lowerLimitActive</cstring> + </property> + <property name="text"> + <string>&Enable alarm</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Enable the minimum value alarm.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>m_lblLowerLimit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Lower limit:</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_lowerLimit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimumSize"> + <size> + <width>70</width> + <height>0</height> + </size> + </property> + </widget> + </hbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>GroupBox1_2</cstring> + </property> + <property name="title"> + <string>Alarm for Maximum Value</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_upperLimitActive</cstring> + </property> + <property name="text"> + <string>E&nable alarm</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Enable the maximum value alarm.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer1_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>m_lblUpperLimit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Upper limit:</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_upperLimit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimumSize"> + <size> + <width>70</width> + <height>0</height> + </size> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>m_lowerLimitActive</sender> + <signal>toggled(bool)</signal> + <receiver>m_lowerLimit</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_upperLimitActive</sender> + <signal>toggled(bool)</signal> + <receiver>m_upperLimit</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_lowerLimitActive</sender> + <signal>toggled(bool)</signal> + <receiver>m_lblLowerLimit</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_upperLimitActive</sender> + <signal>toggled(bool)</signal> + <receiver>m_lblUpperLimit</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<includes> + <include location="global" impldecl="in implementation">kdialog.h</include> + <include location="global" impldecl="in implementation">knumvalidator.h</include> + <include location="local" impldecl="in implementation">SensorLoggerDlgWidget.ui.h</include> +</includes> +<functions> + <function access="private" specifier="non virtual">init()</function> + <function specifier="non virtual" returnType="QString">fileName()</function> + <function specifier="non virtual" returnType="int">timerInterval()</function> + <function specifier="non virtual" returnType="bool">lowerLimitActive()</function> + <function specifier="non virtual" returnType="double">lowerLimit()</function> + <function returnType="bool">upperLimitActive()</function> + <function specifier="non virtual" returnType="double">upperLimit()</function> + <function specifier="non virtual">setFileName( const QString & url )</function> + <function specifier="non virtual">setTimerInterval( int i )</function> + <function specifier="non virtual">setLowerLimitActive( bool b )</function> + <function specifier="non virtual">setLowerLimit( double d )</function> + <function specifier="non virtual">setUpperLimitActive( bool b )</function> + <function specifier="non virtual">setUpperLimit( double d )</function> +</functions> + +<layoutdefaults spacing="6" margin="11"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerDlgWidget.ui.h b/ksysguard/gui/SensorDisplayLib/SensorLoggerDlgWidget.ui.h new file mode 100644 index 000000000..afe0767e9 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLoggerDlgWidget.ui.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + +void SensorLoggerDlgWidget::init() +{ + m_lowerLimit->setValidator(new KDoubleValidator(m_lowerLimit)); + m_upperLimit->setValidator(new KDoubleValidator(m_upperLimit)); + m_timerInterval->setRange(1, 99, 1, true); + + m_fileName->setFocus(); +} + + +QString SensorLoggerDlgWidget::fileName() +{ + return m_fileName->url(); +} + + +int SensorLoggerDlgWidget::timerInterval() +{ + return m_timerInterval->value(); +} + + +bool SensorLoggerDlgWidget::lowerLimitActive() +{ + return m_lowerLimitActive->isChecked(); +} + + +double SensorLoggerDlgWidget::lowerLimit() +{ + return m_lowerLimit->text().toDouble(); +} + + +bool SensorLoggerDlgWidget::upperLimitActive() +{ + return m_upperLimitActive->isChecked(); +} + + +double SensorLoggerDlgWidget::upperLimit() +{ + return m_upperLimit->text().toDouble(); +} + + +void SensorLoggerDlgWidget::setFileName( const QString &url ) +{ + m_fileName->setURL(url); +} + + +void SensorLoggerDlgWidget::setTimerInterval( int i ) +{ + m_timerInterval->setValue(i); +} + + +void SensorLoggerDlgWidget::setLowerLimitActive( bool b ) +{ + m_lowerLimitActive->setChecked(b); +} + + +void SensorLoggerDlgWidget::setLowerLimit( double d ) +{ + m_lowerLimit->setText(QString("%1").arg(d)); +} + + +void SensorLoggerDlgWidget::setUpperLimitActive( bool b ) +{ + m_upperLimitActive->setChecked(b); +} + + +void SensorLoggerDlgWidget::setUpperLimit( double d ) +{ + m_upperLimit->setText(QString("%1").arg(d)); +} diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerSettings.cc b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettings.cc new file mode 100644 index 000000000..568108547 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettings.cc @@ -0,0 +1,77 @@ +/* This file is part of the KDE project + Copyright ( C ) 2003 Nadeem Hasan <nhasan@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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "SensorLoggerSettings.h" +#include "SensorLoggerSettingsWidget.h" + +#include <klocale.h> + +SensorLoggerSettings::SensorLoggerSettings( QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n( "Sensor Logger Settings" ), + Ok|Apply|Cancel, Ok, true ) +{ + m_settingsWidget = new SensorLoggerSettingsWidget( this, "m_settingsWidget" ); + setMainWidget( m_settingsWidget ); +} + +QString SensorLoggerSettings::title() +{ + return m_settingsWidget->title(); +} + +QColor SensorLoggerSettings::foregroundColor() +{ + return m_settingsWidget->foregroundColor(); +} + +QColor SensorLoggerSettings::backgroundColor() +{ + return m_settingsWidget->backgroundColor(); +} + +QColor SensorLoggerSettings::alarmColor() +{ + return m_settingsWidget->alarmColor(); +} + +void SensorLoggerSettings::setTitle( const QString &title ) +{ + m_settingsWidget->setTitle( title ); +} + +void SensorLoggerSettings::setBackgroundColor( const QColor &c ) +{ + m_settingsWidget->setBackgroundColor( c ); +} + +void SensorLoggerSettings::setForegroundColor( const QColor &c ) +{ + m_settingsWidget->setForegroundColor( c ); +} + +void SensorLoggerSettings::setAlarmColor( const QColor &c ) +{ + m_settingsWidget->setAlarmColor( c ); +} + +#include "SensorLoggerSettings.moc" + +/* vim: et sw=2 ts=2 +*/ + diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerSettings.h b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettings.h new file mode 100644 index 000000000..639f55944 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettings.h @@ -0,0 +1,57 @@ +/* This file is part of the KDE project + Copyright ( C ) 2003 Nadeem Hasan <nhasan@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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#ifndef SENSORLOGGERSETTINGS_H +#define SENSORLOGGERSETTINGS_H + +#include <kdialogbase.h> + +#include <qstring.h> +#include <qcolor.h> + +class SensorLoggerSettingsWidget; + +class SensorLoggerSettings : public KDialogBase +{ + Q_OBJECT + + public: + + SensorLoggerSettings( QWidget *parent=0, const char *name=0 ); + + QString title(); + QColor foregroundColor(); + QColor backgroundColor(); + QColor alarmColor(); + + void setTitle( const QString & ); + void setForegroundColor( const QColor & ); + void setBackgroundColor( const QColor & ); + void setAlarmColor( const QColor & ); + + private: + + SensorLoggerSettingsWidget *m_settingsWidget; +}; + +#endif // SENSORLOGGERSETTINGS_H + +/* vim: et sw=2 ts=2 +*/ diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerSettingsWidget.ui b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettingsWidget.ui new file mode 100644 index 000000000..c86e671b2 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettingsWidget.ui @@ -0,0 +1,180 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>SensorLoggerSettingsWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>SensorLoggerSettingsWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>415</width> + <height>202</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>titleFrame</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="title"> + <string>Title</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>m_title</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>colorFrame</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>Box</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="title"> + <string>Colors</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter|AlignLeft</set> + </property> + <property name="vAlign" stdset="0"> + </property> + <property name="wordwrap" stdset="0"> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Text color:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Background color:</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Alarm color:</string> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_foregroundColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>0</red> + <green>255</green> + <blue>0</blue> + </color> + </property> + </widget> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_backgroundColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="KColorButton"> + <property name="name"> + <cstring>m_alarmColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="color"> + <color> + <red>255</red> + <green>0</green> + <blue>0</blue> + </color> + </property> + </widget> + </vbox> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<includes> + <include location="global" impldecl="in implementation">kdialog.h</include> + <include location="local" impldecl="in implementation">SensorLoggerSettingsWidget.ui.h</include> +</includes> +<functions> + <function specifier="non virtual" returnType="QString">title()</function> + <function specifier="non virtual" returnType="QColor">foregroundColor()</function> + <function specifier="non virtual" returnType="QColor">backgroundColor()</function> + <function specifier="non virtual" returnType="QColor">alarmColor()</function> + <function specifier="non virtual">setTitle( const QString & t )</function> + <function specifier="non virtual">setForegroundColor( const QColor & c )</function> + <function specifier="non virtual">setBackgroundColor( const QColor & c )</function> + <function specifier="non virtual">setAlarmColor( const QColor & c )</function> +</functions> +<layoutdefaults spacing="6" margin="11"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +</UI> diff --git a/ksysguard/gui/SensorDisplayLib/SensorLoggerSettingsWidget.ui.h b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettingsWidget.ui.h new file mode 100644 index 000000000..751366466 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SensorLoggerSettingsWidget.ui.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + + +QString SensorLoggerSettingsWidget::title() +{ + return m_title->text(); +} + + +QColor SensorLoggerSettingsWidget::foregroundColor() +{ + return m_foregroundColor->color(); +} + + +QColor SensorLoggerSettingsWidget::backgroundColor() +{ + return m_backgroundColor->color(); +} + + +QColor SensorLoggerSettingsWidget::alarmColor() +{ + return m_alarmColor->color(); +} + + +void SensorLoggerSettingsWidget::setTitle( const QString &t ) +{ + m_title->setText(t); +} + + +void SensorLoggerSettingsWidget::setForegroundColor( const QColor &c ) +{ + m_foregroundColor->setColor(c); +} + + +void SensorLoggerSettingsWidget::setBackgroundColor( const QColor &c ) +{ + m_backgroundColor->setColor(c); +} + + +void SensorLoggerSettingsWidget::setAlarmColor( const QColor &c ) +{ + m_alarmColor->setColor(c); +} diff --git a/ksysguard/gui/SensorDisplayLib/SignalPlotter.cc b/ksysguard/gui/SensorDisplayLib/SignalPlotter.cc new file mode 100644 index 000000000..f8ad121f1 --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SignalPlotter.cc @@ -0,0 +1,648 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <math.h> +#include <string.h> + +#include <qpainter.h> +#include <qpixmap.h> + +#include <kdebug.h> +#include <kglobal.h> + +#include <ksgrd/StyleEngine.h> + +#include "SignalPlotter.h" + +SignalPlotter::SignalPlotter( QWidget *parent, const char *name ) + : QWidget( parent, name ) +{ + // Auto deletion does not work for pointer to arrays. + mBeamData.setAutoDelete( false ); + + setBackgroundMode( NoBackground ); + mShowThinFrame = true; + mSamples = 0; + mMinValue = mMaxValue = 0.0; + mUseAutoRange = true; + + mGraphStyle = GRAPH_POLYGON; + + // Anything smaller than this does not make sense. + setMinimumSize( 16, 16 ); + setSizePolicy( QSizePolicy( QSizePolicy::Expanding, + QSizePolicy::Expanding, false ) ); + + mShowVerticalLines = true; + mVerticalLinesColor = KSGRD::Style->firstForegroundColor(); + mVerticalLinesDistance = 30; + mVerticalLinesScroll = true; + mVerticalLinesOffset = 0; + mHorizontalScale = 1; + + mShowHorizontalLines = true; + mHorizontalLinesColor = KSGRD::Style->secondForegroundColor(); + mHorizontalLinesCount = 5; + + mShowLabels = true; + mShowTopBar = false; + mFontSize = KSGRD::Style->fontSize(); + + mBackgroundColor = KSGRD::Style->backgroundColor(); +} + +SignalPlotter::~SignalPlotter() +{ + for ( double* p = mBeamData.first(); p; p = mBeamData.next() ) + delete [] p; +} + +bool SignalPlotter::addBeam( const QColor &color ) +{ + double* d = new double[ mSamples ]; + memset( d, 0, sizeof(double) * mSamples ); + mBeamData.append( d ); + mBeamColor.append( color ); + + return true; +} + +void SignalPlotter::addSample( const QValueList<double>& sampleBuf ) +{ + if ( mBeamData.count() != sampleBuf.count() ) + return; + + double* d; + if ( mUseAutoRange ) { + double sum = 0; + for ( d = mBeamData.first(); d; d = mBeamData.next() ) { + sum += d[ 0 ]; + if ( sum < mMinValue ) + mMinValue = sum; + if ( sum > mMaxValue ) + mMaxValue = sum; + } + } + + /* If the vertical lines are scrolling, increment the offset + * so they move with the data. The vOffset / hScale confusion + * is because v refers to Vertical Lines, and h to the horizontal + * distance between the vertical lines. */ + if ( mVerticalLinesScroll ) { + mVerticalLinesOffset = ( mVerticalLinesOffset + mHorizontalScale) + % mVerticalLinesDistance; + } + + // Shift data buffers one sample down and insert new samples. + QValueList<double>::ConstIterator s; + for ( d = mBeamData.first(), s = sampleBuf.begin(); d; d = mBeamData.next(), ++s ) { + memmove( d, d + 1, ( mSamples - 1 ) * sizeof( double ) ); + d[ mSamples - 1 ] = *s; + } + + update(); +} + +void SignalPlotter::reorderBeams( const QValueList<int>& newOrder ) +{ + if(newOrder.count() != mBeamData.count()) { + kdDebug() << "Serious problem in move sample" << endl; + return; + } + QPtrList<double> newBeamData; + QValueList<QColor> newBeamColor; + + for(uint i = 0; i < newOrder.count(); i++) { + int newIndex = newOrder[i]; + newBeamData.append(mBeamData.at(newIndex)); + newBeamColor.append(*mBeamColor.at(newIndex)); + } + mBeamData = newBeamData; + mBeamColor = newBeamColor; + +} + +void SignalPlotter::changeRange( int beam, double min, double max ) +{ + // Only the first beam affects range calculation. + if ( beam > 1 ) + return; + + mMinValue = min; + mMaxValue = max; +} + +QValueList<QColor> &SignalPlotter::beamColors() +{ + return mBeamColor; +} + +void SignalPlotter::removeBeam( uint pos ) +{ + mBeamColor.remove( mBeamColor.at( pos ) ); + double *p = mBeamData.take( pos ); + delete [] p; +} + +void SignalPlotter::setTitle( const QString &title ) +{ + mTitle = title; +} + +QString SignalPlotter::title() const +{ + return mTitle; +} + +void SignalPlotter::setUseAutoRange( bool value ) +{ + mUseAutoRange = value; +} + +bool SignalPlotter::useAutoRange() const +{ + return mUseAutoRange; +} + +void SignalPlotter::setMinValue( double min ) +{ + mMinValue = min; +} + +double SignalPlotter::minValue() const +{ + return ( mUseAutoRange ? 0 : mMinValue ); +} + +void SignalPlotter::setMaxValue( double max ) +{ + mMaxValue = max; +} + +double SignalPlotter::maxValue() const +{ + return ( mUseAutoRange ? 0 : mMaxValue ); +} + +void SignalPlotter::setGraphStyle( uint style ) +{ + mGraphStyle = style; +} + +uint SignalPlotter::graphStyle() const +{ + return mGraphStyle; +} + +void SignalPlotter::setHorizontalScale( uint scale ) +{ + if (scale == mHorizontalScale) + return; + + mHorizontalScale = scale; + if (isVisible()) + updateDataBuffers(); +} + +int SignalPlotter::horizontalScale() const +{ + return mHorizontalScale; +} + +void SignalPlotter::setShowVerticalLines( bool value ) +{ + mShowVerticalLines = value; +} + +bool SignalPlotter::showVerticalLines() const +{ + return mShowVerticalLines; +} + +void SignalPlotter::setVerticalLinesColor( const QColor &color ) +{ + mVerticalLinesColor = color; +} + +QColor SignalPlotter::verticalLinesColor() const +{ + return mVerticalLinesColor; +} + +void SignalPlotter::setVerticalLinesDistance( int distance ) +{ + mVerticalLinesDistance = distance; +} + +int SignalPlotter::verticalLinesDistance() const +{ + return mVerticalLinesDistance; +} + +void SignalPlotter::setVerticalLinesScroll( bool value ) +{ + mVerticalLinesScroll = value; +} + +bool SignalPlotter::verticalLinesScroll() const +{ + return mVerticalLinesScroll; +} + +void SignalPlotter::setShowHorizontalLines( bool value ) +{ + mShowHorizontalLines = value; +} + +bool SignalPlotter::showHorizontalLines() const +{ + return mShowHorizontalLines; +} + +void SignalPlotter::setHorizontalLinesColor( const QColor &color ) +{ + mHorizontalLinesColor = color; +} + +QColor SignalPlotter::horizontalLinesColor() const +{ + return mHorizontalLinesColor; +} + +void SignalPlotter::setHorizontalLinesCount( int count ) +{ + mHorizontalLinesCount = count; +} + +int SignalPlotter::horizontalLinesCount() const +{ + return mHorizontalLinesCount; +} + +void SignalPlotter::setShowLabels( bool value ) +{ + mShowLabels = value; +} + +bool SignalPlotter::showLabels() const +{ + return mShowLabels; +} + +void SignalPlotter::setShowTopBar( bool value ) +{ + mShowTopBar = value; +} + +bool SignalPlotter::showTopBar() const +{ + return mShowTopBar; +} + +void SignalPlotter::setFontSize( int size ) +{ + mFontSize = size; +} + +int SignalPlotter::fontSize() const +{ + return mFontSize; +} + +void SignalPlotter::setBackgroundColor( const QColor &color ) +{ + mBackgroundColor = color; +} + +QColor SignalPlotter::backgroundColor() const +{ + return mBackgroundColor; +} + +void SignalPlotter::resizeEvent( QResizeEvent* ) +{ + Q_ASSERT( width() > 2 ); + + updateDataBuffers(); +} + +void SignalPlotter::updateDataBuffers() +{ + /* Since the data buffers for the beams are equal in size to the + * width of the widget minus 2 we have to enlarge or shrink the + * buffers accordingly when a resize occures. To have a nicer + * display we try to keep as much data as possible. Data that is + * lost due to shrinking the buffers cannot be recovered on + * enlarging though. */ + + /* Determine new number of samples first. + * +0.5 to ensure rounding up + * +2 for extra data points so there is + * 1) no wasted space and + * 2) no loss of precision when drawing the first data point. */ + uint newSampleNum = static_cast<uint>( ( ( width() - 2 ) / + mHorizontalScale ) + 2.5 ); + + // overlap between the old and the new buffers. + int overlap = kMin( mSamples, newSampleNum ); + + for ( uint i = 0; i < mBeamData.count(); ++i ) { + double* nd = new double[ newSampleNum ]; + + // initialize new part of the new buffer + if ( newSampleNum > (uint)overlap ) + memset( nd, 0, sizeof( double ) * ( newSampleNum - overlap ) ); + + // copy overlap from old buffer to new buffer + memcpy( nd + ( newSampleNum - overlap ), mBeamData.at( i ) + + ( mSamples - overlap ), overlap * sizeof( double ) ); + + double *p = mBeamData.take( i ); + delete [] p; + mBeamData.insert( i, nd ); + } + + mSamples = newSampleNum; +} + +void SignalPlotter::paintEvent( QPaintEvent* ) +{ + uint w = width(); + uint h = height(); + + /* Do not do repaints when the widget is not yet setup properly. */ + if ( w <= 2 ) + return; + + QPixmap pm( w, h ); + QPainter p; + p.begin( &pm, this ); + + pm.fill( mBackgroundColor ); + /* Draw white line along the bottom and the right side of the + * widget to create a 3D like look. */ + p.setPen( QColor( colorGroup().light() ) ); + if(mShowThinFrame) { + p.drawLine( 0, h - 1, w - 1, h - 1 ); + p.drawLine( w - 1, 0, w - 1, h - 1 ); + + h--; + w--; + p.setClipRect( 0, 0, w, h ); + } + double range = mMaxValue - mMinValue; + + /* If the range is too small we will force it to 1.0 since it + * looks a lot nicer. */ + if ( range < 0.000001 ) + range = 1.0; + + double minValue = mMinValue; + if ( mUseAutoRange ) { + if ( mMinValue != 0.0 ) { + double dim = pow( 10, floor( log10( fabs( mMinValue ) ) ) ) / 2; + if ( mMinValue < 0.0 ) + minValue = dim * floor( mMinValue / dim ); + else + minValue = dim * ceil( mMinValue / dim ); + range = mMaxValue - minValue; + if ( range < 0.000001 ) + range = 1.0; + } + // Massage the range so that the grid shows some nice values. + double step = range / (mHorizontalLinesCount+1); + double dim = pow( 10, floor( log10( step ) ) ) / 2; + range = dim * ceil( step / dim ) * (mHorizontalLinesCount+1); + } + double maxValue = minValue + range; + + int top = 0; + if ( mShowTopBar && h > ( mFontSize/*top bar size*/ + 2/*padding*/ +5/*smallest reasonable size for a graph*/ ) ) { + /* Draw horizontal bar with current sensor values at top of display. */ + p.setPen( mHorizontalLinesColor ); + int x0 = w / 2; + p.setFont( QFont( p.font().family(), mFontSize ) ); + top = p.fontMetrics().height(); + h -= top; + int h0 = top - 2; // h0 is our new top. It's at least 5 pixels high + p.drawText(0, 0, x0, top - 2, Qt::AlignCenter, mTitle ); + + p.drawLine( x0 - 1, 1, x0 - 1, h0 ); + p.drawLine( 0, top - 1, w - 2, top - 1 ); + + double bias = -minValue; + double scaleFac = ( w - x0 - 2 ) / range; + QValueList<QColor>::Iterator col; + col = mBeamColor.begin(); + for ( double* d = mBeamData.first(); d; d = mBeamData.next(), ++col ) { + int start = x0 + (int)( bias * scaleFac ); + int end = x0 + (int)( ( bias += d[ mSamples - 1 ] ) * scaleFac ); + /* If the rect is wider than 2 pixels we draw only the last + * pixels with the bright color. The rest is painted with + * a 50% darker color. */ + if ( end - start > 1 ) { + p.setPen( (*col).dark( 150 ) ); + p.setBrush( (*col).dark( 150 ) ); + p.drawRect( start, 1, end - start, h0 ); + p.setPen( *col ); + p.drawLine( end, 1, end, h0 ); + } else if ( start - end > 1 ) { + p.setPen( (*col).dark( 150 ) ); + p.setBrush( (*col).dark( 150 ) ); + p.drawRect( end, 1, start - end, h0 ); + p.setPen( *col ); + p.drawLine( end, 1, end, h0 ); + } else { + p.setPen( *col ); + p.drawLine( start, 1, start, h0 ); + } + } + } + + /* Draw scope-like grid vertical lines */ + if ( mShowVerticalLines && w > 60 ) { + p.setPen( mVerticalLinesColor ); + for ( uint x = mVerticalLinesOffset; x < ( w - 2 ); x += mVerticalLinesDistance ) + p.drawLine( w - x, top, w - x, h + top - 2 ); + } + + /* In autoRange mode we determine the range and plot the values in + * one go. This is more efficiently than running through the + * buffers twice but we do react on recently discarded samples as + * well as new samples one plot too late. So the range is not + * correct if the recently discarded samples are larger or smaller + * than the current extreme values. But we can probably live with + * this. */ + if ( mUseAutoRange ) + mMinValue = mMaxValue = 0.0; + + /* Plot stacked values */ + double scaleFac = ( h - 2 ) / range; + if ( mGraphStyle == GRAPH_ORIGINAL ) { + int xPos = 0; + for ( int i = 0; i < mSamples; i++, xPos += mHorizontalScale ) { + double bias = -minValue; + QValueList<QColor>::Iterator col; + col = mBeamColor.begin(); + double sum = 0.0; + for ( double* d = mBeamData.first(); d; d = mBeamData.next(), ++col ) { + if ( mUseAutoRange ) { + sum += d[ i ]; + if ( sum < mMinValue ) + mMinValue = sum; + if ( sum > mMaxValue ) + mMaxValue = sum; + } + int start = top + h - 2 - (int)( bias * scaleFac ); + int end = top + h - 2 - (int)( ( bias + d[ i ] ) * scaleFac ); + bias += d[ i ]; + /* If the line is longer than 2 pixels we draw only the last + * 2 pixels with the bright color. The rest is painted with + * a 50% darker color. */ + if ( end - start > 2 ) { + p.fillRect( xPos, start, mHorizontalScale, end - start - 1, (*col).dark( 150 ) ); + p.fillRect( xPos, end - 1, mHorizontalScale, 2, *col ); + } else if ( start - end > 2 ) { + p.fillRect( xPos, start, mHorizontalScale, end - start + 1, (*col).dark( 150 ) ); + p.fillRect( xPos, end + 1, mHorizontalScale, 2, *col ); + } else + p.fillRect( xPos, start, mHorizontalScale, end - start, *col ); + + } + } + } else if ( mGraphStyle == GRAPH_POLYGON ) { + int *prevVals = new int[ mBeamData.count() ]; + int hack[ 4 ]; + hack[ 0 ] = hack[ 1 ] = hack[ 2 ] = hack[ 3 ] = 0; + int x1 = w - ( ( mSamples + 1 ) * mHorizontalScale ); + + for ( int i = 0; i < mSamples; i++ ) { + QValueList<QColor>::Iterator col; + col = mBeamColor.begin(); + double sum = 0.0; + int y = top + h - 2; + int oldY = top + h; + int oldPrevY = oldY; + int height = 0; + int j = 0; + int jMax = mBeamData.count() - 1; + x1 += mHorizontalScale; + int x2 = x1 + mHorizontalScale; + + for ( double* d = mBeamData.first(); d; d = mBeamData.next(), ++col, j++ ) { + if ( mUseAutoRange ) { + sum += d[ i ]; + if ( sum < mMinValue ) + mMinValue = sum; + if ( sum > mMaxValue ) + mMaxValue = sum; + } + height = (int)( ( d[ i ] - minValue ) * scaleFac ); + y -= height; + + /* If the line is longer than 2 pixels we draw only the last + * 2 pixels with the bright color. The rest is painted with + * a 50% darker color. */ + QPen lastPen = QPen( p.pen() ); + p.setPen( (*col).dark( 150 ) ); + p.setBrush( (*col).dark( 150 ) ); + QPointArray pa( 4 ); + int prevY = ( i == 0 ) ? y : prevVals[ j ]; + pa.putPoints( 0, 1, x1, prevY ); + pa.putPoints( 1, 1, x2, y ); + pa.putPoints( 2, 1, x2, oldY ); + pa.putPoints( 3, 1, x1, oldPrevY ); + p.drawPolygon( pa ); + p.setPen( lastPen ); + if ( jMax == 0 ) { + // draw as normal, no deferred drawing req'd. + p.setPen( *col ); + p.drawLine( x1, prevY, x2, y ); + } else if ( j == jMax ) { + // draw previous values and current values + p.drawLine( hack[ 0 ], hack[ 1 ], hack[ 2 ], hack[ 3 ] ); + p.setPen( *col ); + p.drawLine( x1, prevY, x2, y ); + } else if ( j == 0 ) { + // save values only + hack[ 0 ] = x1; + hack[ 1 ] = prevY; + hack[ 2 ] = x2; + hack[ 3 ] = y; + p.setPen( *col ); + } else { + p.drawLine( hack[ 0 ], hack[ 1 ], hack[ 2 ], hack[ 3 ] ); + hack[ 0 ] = x1; + hack[ 1 ] = prevY; + hack[ 2 ] = x2; + hack[ 3 ] = y; + p.setPen( *col ); + } + + prevVals[ j ] = y; + oldY = y; + oldPrevY = prevY; + } + } + + delete[] prevVals; + } + + /* Draw horizontal lines and values. Lines are always drawn. + * Values are only draw when width is greater than 60 */ + if ( mShowHorizontalLines ) { + p.setPen( mHorizontalLinesColor ); + p.setFont( QFont( p.font().family(), mFontSize ) ); + QString val; + + /* top = 0 or font.height depending on whether there's a topbar or not + * h = graphing area.height - i.e. the actual space we have to draw inside + * + * Note we are drawing from 0,0 as the top left corner. So we have to add on top to get to the top of where we are drawing + * so top+h is the height of the widget + */ + for ( uint y = 1; y <= mHorizontalLinesCount; y++ ) { + + int y_coord = top + (y * h) / (mHorizontalLinesCount+1); //Make sure it's y*h first to avoid rounding bugs + p.drawLine( 0, y_coord, w - 2, y_coord ); + + if ( mShowLabels && h > ( mFontSize + 1 ) * ( mHorizontalLinesCount + 1 ) + && w > 60 ) { + val = QString::number(maxValue - (y * range) / (mHorizontalLinesCount+1 ) ); + p.drawText( 6, y_coord - 1, val ); //draw the text one pixel raised above the line + } + } + + //Draw the bottom most (minimum) number as well + if ( mShowLabels && h > ( mFontSize + 1 ) * ( mHorizontalLinesCount + 1 ) + && w > 60 ) { + val = QString::number( minValue ); + p.drawText( 6, top + h - 2, val ); + } + } + + p.end(); + bitBlt( this, 0, 0, &pm ); +} + +#include "SignalPlotter.moc" diff --git a/ksysguard/gui/SensorDisplayLib/SignalPlotter.h b/ksysguard/gui/SensorDisplayLib/SignalPlotter.h new file mode 100644 index 000000000..9a9544b3c --- /dev/null +++ b/ksysguard/gui/SensorDisplayLib/SignalPlotter.h @@ -0,0 +1,147 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_SIGNALPLOTTER_H +#define KSG_SIGNALPLOTTER_H + +#include <qptrlist.h> +#include <qstring.h> +#include <qvaluelist.h> +#include <qwidget.h> + +#define GRAPH_POLYGON 0 +#define GRAPH_ORIGINAL 1 + +class QColor; + +class SignalPlotter : public QWidget +{ + Q_OBJECT + + public: + SignalPlotter( QWidget *parent = 0, const char *name = 0 ); + ~SignalPlotter(); + + bool addBeam( const QColor &color ); + void addSample( const QValueList<double> &samples ); + + void removeBeam( uint pos ); + + void changeRange( int beam, double min, double max ); + + QValueList<QColor> &beamColors(); + + void setTitle( const QString &title ); + QString title() const; + + void setUseAutoRange( bool value ); + bool useAutoRange() const; + + void setMinValue( double min ); + double minValue() const; + + void setMaxValue( double max ); + double maxValue() const; + + void setGraphStyle( uint style ); + uint graphStyle() const; + + void setHorizontalScale( uint scale ); + int horizontalScale() const; + + void setShowVerticalLines( bool value ); + bool showVerticalLines() const; + + void setVerticalLinesColor( const QColor &color ); + QColor verticalLinesColor() const; + + void setVerticalLinesDistance( int distance ); + int verticalLinesDistance() const; + + void setVerticalLinesScroll( bool value ); + bool verticalLinesScroll() const; + + void setShowHorizontalLines( bool value ); + bool showHorizontalLines() const; + + void setHorizontalLinesColor( const QColor &color ); + QColor horizontalLinesColor() const; + + void setHorizontalLinesCount( int count ); + int horizontalLinesCount() const; + + void setShowLabels( bool value ); + bool showLabels() const; + + void setShowTopBar( bool value ); + bool showTopBar() const; + + void setFontSize( int size ); + int fontSize() const; + + void setBackgroundColor( const QColor &color ); + QColor backgroundColor() const; + void reorderBeams( const QValueList<int>& newOrder ); + + void setThinFrame(bool set) { mShowThinFrame = set; } + + protected: + void updateDataBuffers(); + + virtual void resizeEvent( QResizeEvent* ); + virtual void paintEvent( QPaintEvent* ); + + private: + double mMinValue; + double mMaxValue; + bool mUseAutoRange; + bool mShowThinFrame; + + uint mGraphStyle; + + bool mShowVerticalLines; + QColor mVerticalLinesColor; + uint mVerticalLinesDistance; + bool mVerticalLinesScroll; + uint mVerticalLinesOffset; + uint mHorizontalScale; + + bool mShowHorizontalLines; + QColor mHorizontalLinesColor; + uint mHorizontalLinesCount; + + bool mShowLabels; + bool mShowTopBar; + uint mFontSize; + + QColor mBackgroundColor; + + QPtrList<double> mBeamData; + QValueList<QColor> mBeamColor; + + unsigned int mSamples; + + QString mTitle; +}; + +#endif diff --git a/ksysguard/gui/SignalIDs.h b/ksysguard/gui/SignalIDs.h new file mode 100644 index 000000000..16df1b1e1 --- /dev/null +++ b/ksysguard/gui/SignalIDs.h @@ -0,0 +1,52 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_SIGNALIDS_H +#define KSG_SIGNALIDS_H + +/* This file is used to correlate the entries of the process popup menu + * of the ProcessList class and the value received by the kill command + * in ksysguardd. We limit the set of available signals to the POSIX.1 + * set with job control. */ + +#define MENU_ID_SIGABRT 11 +#define MENU_ID_SIGALRM 12 +#define MENU_ID_SIGCHLD 13 +#define MENU_ID_SIGCONT 14 +#define MENU_ID_SIGFPE 15 +#define MENU_ID_SIGHUP 16 +#define MENU_ID_SIGILL 17 +#define MENU_ID_SIGINT 18 +#define MENU_ID_SIGKILL 19 +#define MENU_ID_SIGPIPE 20 +#define MENU_ID_SIGQUIT 21 +#define MENU_ID_SIGSEGV 22 +#define MENU_ID_SIGSTOP 23 +#define MENU_ID_SIGTERM 24 +#define MENU_ID_SIGTSTP 25 +#define MENU_ID_SIGTTIN 26 +#define MENU_ID_SIGTTOU 27 +#define MENU_ID_SIGUSR1 28 +#define MENU_ID_SIGUSR2 29 + +#endif diff --git a/ksysguard/gui/SystemLoad.sgrd b/ksysguard/gui/SystemLoad.sgrd new file mode 100644 index 000000000..139187e93 --- /dev/null +++ b/ksysguard/gui/SystemLoad.sgrd @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE KSysGuardWorkSheet> +<WorkSheet rows="2" interval="2" columns="2" > + <host port="-1" shell="" name="localhost" command="ksysguardd" /> + <display topBar="0" vColor="326429" title="CPU Load" bColor="3223601" graphStyle="0" class="FancyPlotter" row="0" unit="" hScale="1" column="0" showUnit="0" hLines="1" hCount="5" vLines="1" autoRange="0" min="0" max="100" hColor="326429" globalUpdate="1" pause="0" fontSize="9" labels="1" vScroll="1" vDistance="30" > + <beam sensorName="cpu/user" hostName="localhost" color="1608191" sensorType="integer" /> + <beam sensorName="cpu/sys" hostName="localhost" color="16743688" sensorType="integer" /> + <beam sensorName="cpu/nice" hostName="localhost" color="16771600" sensorType="integer" /> + </display> + <display topBar="0" vColor="326429" title="Load Average (1 min)" bColor="3223601" graphStyle="0" class="FancyPlotter" row="0" unit="" hScale="1" column="1" showUnit="0" hLines="1" hCount="5" vLines="1" autoRange="1" min="0" max="0" hColor="326429" globalUpdate="1" pause="0" fontSize="9" labels="1" vScroll="1" vDistance="30" > + <beam sensorName="cpu/loadavg1" hostName="localhost" color="1608191" sensorType="float" /> + </display> + <display topBar="0" vColor="326429" title="Physical Memory" +bColor="3223601" graphStyle="0" class="FancyPlotter" row="1" unit="" +hScale="1" column="0" showUnit="0" hLines="1" hCount="5" vLines="1" +autoRange="0" min="0" max="0" hColor="326429" globalUpdate="1" pause="0" fontSize="9" labels="1" vScroll="1" vDistance="30" > + <beam sensorName="mem/physical/application" hostName="localhost" color="1608191" sensorType="integer" /> + <beam sensorName="mem/physical/buf" hostName="localhost" color="16743688" sensorType="integer" /> + <beam sensorName="mem/physical/cached" hostName="localhost" color="16771600" sensorType="integer" /> + </display> + <display topBar="0" vColor="326429" title="Swap Memory" +bColor="3223601" graphStyle="0" class="FancyPlotter" row="1" unit="" +hScale="1" column="1" showUnit="0" hLines="1" hCount="5" vLines="1" +autoRange="0" min="0" max="0" hColor="326429" globalUpdate="1" pause="0" fontSize="9" labels="1" vScroll="1" vDistance="30" > + <beam sensorName="mem/swap/used" hostName="localhost" color="1608191" sensorType="integer" /> + </display> +</WorkSheet> diff --git a/ksysguard/gui/Taskmanager.ktop b/ksysguard/gui/Taskmanager.ktop new file mode 100644 index 000000000..00e5ec5ce --- /dev/null +++ b/ksysguard/gui/Taskmanager.ktop @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE KSysGuardWorkSheet > +<WorkSheet rows="1" columns="1"> +<host name="localhost" shell="" command="ksysguardd"/> +<display row="0" column="0" class="ProcessController" hostName="localhost" sensorName="ps" sensorType="table" tree="off" pause="off" filter="0"> +</display> +</WorkSheet> diff --git a/ksysguard/gui/WorkSheet.cc b/ksysguard/gui/WorkSheet.cc new file mode 100644 index 000000000..f6555a1c6 --- /dev/null +++ b/ksysguard/gui/WorkSheet.cc @@ -0,0 +1,698 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <qclipboard.h> +#include <qcursor.h> +#include <qdragobject.h> +#include <qfile.h> +#include <qlayout.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kpopupmenu.h> + +#include <SensorManager.h> + +#include "DancingBars.h" +#include "DummyDisplay.h" +#include "FancyPlotter.h" +#include "ListView.h" +#include "LogFile.h" +#include "MultiMeter.h" +#include "ProcessController.h" +#include "SensorLogger.h" +#include "WorkSheet.h" +#include "WorkSheetSettings.h" + +WorkSheet::WorkSheet( QWidget *parent, const char *name ) + : QWidget( parent, name ) +{ + mGridLayout = 0; + mRows = mColumns = 0; + mDisplayList = 0; + mModified = false; + mFileName = ""; + + setAcceptDrops( true ); +} + +WorkSheet::WorkSheet( uint rows, uint columns, uint interval, QWidget* parent, + const char *name ) + : QWidget( parent, name ) +{ + mRows = mColumns = 0; + mGridLayout = 0; + mDisplayList = 0; + updateInterval( interval ); + mModified = false; + mFileName = ""; + + createGrid( rows, columns ); + + // Initialize worksheet with dummy displays. + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + replaceDisplay( r, c ); + + mGridLayout->activate(); + + setAcceptDrops( true ); +} + +WorkSheet::~WorkSheet() +{ +} + +bool WorkSheet::load( const QString &fileName ) +{ + setModified( false ); + + mFileName = fileName; + QFile file( mFileName ); + if ( !file.open( IO_ReadOnly ) ) { + KMessageBox::sorry( this, i18n( "Cannot open the file %1." ).arg( mFileName ) ); + return false; + } + + QDomDocument doc; + + // Read in file and check for a valid XML header. + if ( !doc.setContent( &file) ) { + KMessageBox::sorry( this, i18n( "The file %1 does not contain valid XML." ) + .arg( mFileName ) ); + return false; + } + + // Check for proper document type. + if ( doc.doctype().name() != "KSysGuardWorkSheet" ) { + KMessageBox::sorry( this, i18n( "The file %1 does not contain a valid worksheet " + "definition, which must have a document type 'KSysGuardWorkSheet'.") + .arg( mFileName ) ); + return false; + } + + // Check for proper size. + QDomElement element = doc.documentElement(); + updateInterval( element.attribute( "interval" ).toUInt() ); + if ( updateInterval() < 1 || updateInterval() > 300 ) + updateInterval( 2 ); + + bool rowsOk, columnsOk; + uint rows = element.attribute( "rows" ).toUInt( &rowsOk ); + uint columns = element.attribute( "columns" ).toUInt( &columnsOk ); + if ( !( rowsOk && columnsOk ) ) { + KMessageBox::sorry( this, i18n("The file %1 has an invalid worksheet size.") + .arg( mFileName ) ); + return false; + } + + createGrid( rows, columns ); + + uint i; + /* Load lists of hosts that are needed for the work sheet and try + * to establish a connection. */ + QDomNodeList dnList = element.elementsByTagName( "host" ); + for ( i = 0; i < dnList.count(); ++i ) { + QDomElement element = dnList.item( i ).toElement(); + bool ok; + int port = element.attribute( "port" ).toInt( &ok ); + if ( !ok ) + port = -1; + KSGRD::SensorMgr->engage( element.attribute( "name" ), + element.attribute( "shell" ), + element.attribute( "command" ), port ); + } + //if no hosts are specified, at least connect to localhost + if(dnList.count() == 0) + KSGRD::SensorMgr->engage( "localhost", "", "ksysguardd", -1); + + // Load the displays and place them into the work sheet. + dnList = element.elementsByTagName( "display" ); + for ( i = 0; i < dnList.count(); ++i ) { + QDomElement element = dnList.item( i ).toElement(); + uint row = element.attribute( "row" ).toUInt(); + uint column = element.attribute( "column" ).toUInt(); + if ( row >= mRows || column >= mColumns) { + kdDebug(1215) << "Row or Column out of range (" << row << ", " + << column << ")" << endl; + return false; + } + + replaceDisplay( row, column, element ); + } + + // Fill empty cells with dummy displays + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + if ( !mDisplayList[ r ][ c ] ) + replaceDisplay( r, c ); + + setModified( false ); + + return true; +} + +bool WorkSheet::save( const QString &fileName ) +{ + mFileName = fileName; + + QDomDocument doc( "KSysGuardWorkSheet" ); + doc.appendChild( doc.createProcessingInstruction( + "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); + + // save work sheet information + QDomElement ws = doc.createElement( "WorkSheet" ); + doc.appendChild( ws ); + ws.setAttribute( "interval", updateInterval() ); + ws.setAttribute( "rows", mRows ); + ws.setAttribute( "columns", mColumns ); + + QStringList hosts; + collectHosts( hosts ); + + // save host information (name, shell, etc.) + QStringList::Iterator it; + for ( it = hosts.begin(); it != hosts.end(); ++it ) { + QString shell, command; + int port; + + if ( KSGRD::SensorMgr->hostInfo( *it, shell, command, port ) ) { + QDomElement host = doc.createElement( "host" ); + ws.appendChild( host ); + host.setAttribute( "name", *it ); + host.setAttribute( "shell", shell ); + host.setAttribute( "command", command ); + host.setAttribute( "port", port ); + } + } + + for ( uint r = 0; r < mRows; ++r ) + for (uint c = 0; c < mColumns; ++c ) + if ( !mDisplayList[ r ][ c ]->isA( "DummyDisplay" ) ) { + KSGRD::SensorDisplay* display = (KSGRD::SensorDisplay*)mDisplayList[ r ][ c ]; + QDomElement element = doc.createElement( "display" ); + ws.appendChild( element ); + element.setAttribute( "row", r ); + element.setAttribute( "column", c ); + element.setAttribute( "class", display->className() ); + + display->saveSettings( doc, element ); + } + + QFile file( mFileName ); + if ( !file.open( IO_WriteOnly ) ) { + KMessageBox::sorry( this, i18n( "Cannot save file %1" ).arg( mFileName ) ); + return false; + } + + QTextStream s( &file ); + s.setEncoding( QTextStream::UnicodeUTF8 ); + s << doc; + file.close(); + + setModified( false ); + + return true; +} + +void WorkSheet::cut() +{ + if ( !currentDisplay() || currentDisplay()->isA( "DummyDisplay" ) ) + return; + + QClipboard* clip = QApplication::clipboard(); + + clip->setText( currentDisplayAsXML() ); + + removeDisplay( currentDisplay() ); +} + +void WorkSheet::copy() +{ + if ( !currentDisplay() || currentDisplay()->isA( "DummyDisplay" ) ) + return; + + QClipboard* clip = QApplication::clipboard(); + + clip->setText( currentDisplayAsXML() ); +} + +void WorkSheet::paste() +{ + uint row, column; + if ( !currentDisplay( &row, &column ) ) + return; + + QClipboard* clip = QApplication::clipboard(); + + QDomDocument doc; + /* Get text from clipboard and check for a valid XML header and + * proper document type. */ + if ( !doc.setContent( clip->text() ) || doc.doctype().name() != "KSysGuardDisplay" ) { + KMessageBox::sorry( this, i18n("The clipboard does not contain a valid display " + "description." ) ); + return; + } + + QDomElement element = doc.documentElement(); + replaceDisplay( row, column, element ); +} + +void WorkSheet::setFileName( const QString &fileName ) +{ + mFileName = fileName; + setModified( true ); +} + +const QString& WorkSheet::fileName() const +{ + return mFileName; +} + +bool WorkSheet::modified() const +{ + return mModified; +} + +void WorkSheet::setTitle( const QString &title ) +{ + mTitle = title; +} + +QString WorkSheet::title() const +{ + return mTitle; +} + +KSGRD::SensorDisplay *WorkSheet::addDisplay( const QString &hostName, + const QString &sensorName, + const QString &sensorType, + const QString& sensorDescr, + uint row, uint column ) +{ + if ( !KSGRD::SensorMgr->engageHost( hostName ) ) { + QString msg = i18n( "It is impossible to connect to \'%1\'." ).arg( hostName ); + KMessageBox::error( this, msg ); + + return 0; + } + + /* If the by 'row' and 'column' specified display is a QGroupBox dummy + * display we replace the widget. Otherwise we just try to add + * the new sensor to an existing display. */ + if ( mDisplayList[ row ][ column ]->isA( "DummyDisplay" ) ) { + KSGRD::SensorDisplay* newDisplay = 0; + /* If the sensor type is supported by more than one display + * type we popup a menu so the user can select what display is + * wanted. */ + if ( sensorType == "integer" || sensorType == "float" ) { + KPopupMenu pm; + pm.insertTitle( i18n( "Select Display Type" ) ); + pm.insertItem( i18n( "&Signal Plotter" ), 1 ); + pm.insertItem( i18n( "&Multimeter" ), 2 ); + pm.insertItem( i18n( "&BarGraph" ), 3 ); + pm.insertItem( i18n( "S&ensorLogger" ), 4 ); + switch ( pm.exec( QCursor::pos() ) ) { + case 1: + newDisplay = new FancyPlotter( this, "FancyPlotter", sensorDescr ); + break; + case 2: + newDisplay = new MultiMeter( this, "MultiMeter", sensorDescr ); + break; + case 3: + newDisplay = new DancingBars( this, "DancingBars", sensorDescr ); + break; + case 4: + newDisplay = new SensorLogger( this, "SensorLogger", sensorDescr ); + break; + default: + return 0; + } + } else if ( sensorType == "listview" ) + newDisplay = new ListView( this, "ListView", sensorDescr ); + else if ( sensorType == "logfile" ) + newDisplay = new LogFile( this, "LogFile", sensorDescr ); + else if ( sensorType == "sensorlogger" ) + newDisplay = new SensorLogger( this, "SensorLogger", sensorDescr ); + else if ( sensorType == "table" ) + newDisplay = new ProcessController( this ); + else { + kdDebug(1215) << "Unkown sensor type: " << sensorType << endl; + return 0; + } + + replaceDisplay( row, column, newDisplay ); + } + + mDisplayList[ row ][ column ]->addSensor( hostName, sensorName, sensorType, sensorDescr ); + + setModified( true ); + + return ((KSGRD::SensorDisplay*)mDisplayList[ row ][ column ] ); +} + +void WorkSheet::settings() +{ + WorkSheetSettings dlg( this ); + + /* The sheet name should be changed with the "Save as..." function, + * so we don't have to display the display frame. */ + dlg.setSheetTitle( mTitle ); + dlg.setRows( mRows ); + dlg.setColumns( mColumns ); + dlg.setInterval( updateInterval() ); + + if ( dlg.exec() ) { + updateInterval( dlg.interval() ); + for (uint r = 0; r < mRows; ++r) + for (uint c = 0; c < mColumns; ++c) + if ( mDisplayList[ r ][ c ]->useGlobalUpdateInterval() ) + mDisplayList[ r ][ c ]->setUpdateInterval( updateInterval() ); + + resizeGrid( dlg.rows(), dlg.columns() ); + + mTitle = dlg.sheetTitle(); + emit titleChanged( this ); + + setModified( true ); + } +} + +void WorkSheet::showPopupMenu( KSGRD::SensorDisplay *display ) +{ + display->configureSettings(); +} + +void WorkSheet::setModified( bool modified ) +{ + if ( modified != mModified ) { + mModified = modified; + if ( !modified ) + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + mDisplayList[ r ][ c ]->setModified( false ); + + emit sheetModified( this ); + } +} + +void WorkSheet::applyStyle() +{ + for ( uint r = 0; r < mRows; ++r ) + for (uint c = 0; c < mColumns; ++c ) + mDisplayList[ r ][ c ]->applyStyle(); +} + +void WorkSheet::dragEnterEvent( QDragEnterEvent *e ) +{ + e->accept( QTextDrag::canDecode( e ) ); +} + +void WorkSheet::dropEvent( QDropEvent *e ) +{ + QString dragObject; + + if ( QTextDrag::decode( e, dragObject) ) { + // The host name, sensor name and type are seperated by a ' '. + QStringList parts = QStringList::split( ' ', dragObject ); + + QString hostName = parts[ 0 ]; + QString sensorName = parts[ 1 ]; + QString sensorType = parts[ 2 ]; + QString sensorDescr = parts[ 3 ]; + + if ( hostName.isEmpty() || sensorName.isEmpty() || sensorType.isEmpty() ) { + return; + } + + /* Find the sensor display that is supposed to get the drop + * event and replace or add sensor. */ + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + if ( mDisplayList[ r ][ c ]->geometry().contains( e->pos() ) ) { + addDisplay( hostName, sensorName, sensorType, sensorDescr, r, c ); + return; + } + } +} + +QSize WorkSheet::sizeHint() const +{ + return QSize( 200,150 ); +} + +void WorkSheet::customEvent( QCustomEvent *e ) +{ + if ( e->type() == QEvent::User ) { + // SensorDisplays send out this event if they want to be removed. + + removeDisplay( (KSGRD::SensorDisplay*)e->data() ); + } +} + +bool WorkSheet::replaceDisplay( uint row, uint column, QDomElement& element ) +{ + QString classType = element.attribute( "class" ); + KSGRD::SensorDisplay* newDisplay; + if ( classType == "FancyPlotter" ) + newDisplay = new FancyPlotter( this ); + else if ( classType == "MultiMeter" ) + newDisplay = new MultiMeter( this ); + else if ( classType == "DancingBars" ) + newDisplay = new DancingBars( this ); + else if ( classType == "ListView" ) + newDisplay = new ListView( this ); + else if ( classType == "LogFile" ) + newDisplay = new LogFile( this ); + else if ( classType == "SensorLogger" ) + newDisplay = new SensorLogger( this ); + else if ( classType == "ProcessController" ) + newDisplay = new ProcessController( this ); + else { + kdDebug(1215) << "Unkown class " << classType << endl; + return false; + } + + if ( newDisplay->useGlobalUpdateInterval() ) + newDisplay->setUpdateInterval( updateInterval() ); + + // load display specific settings + if ( !newDisplay->restoreSettings( element ) ) + return false; + + replaceDisplay( row, column, newDisplay ); + + return true; +} + +void WorkSheet::replaceDisplay( uint row, uint column, KSGRD::SensorDisplay* newDisplay ) +{ + // remove the old display at this location + delete mDisplayList[ row ][ column ]; + + // insert new display + if ( !newDisplay ) + mDisplayList[ row ][ column ] = new DummyDisplay( this, "DummyDisplay" ); + else { + mDisplayList[ row ][ column ] = newDisplay; + if ( mDisplayList[ row ][ column ]->useGlobalUpdateInterval() ) + mDisplayList[ row ][ column ]->setUpdateInterval( updateInterval() ); + connect( newDisplay, SIGNAL( showPopupMenu( KSGRD::SensorDisplay* ) ), + SLOT( showPopupMenu( KSGRD::SensorDisplay* ) ) ); + connect( newDisplay, SIGNAL( modified( bool ) ), + SLOT( setModified( bool ) ) ); + } + + + mGridLayout->addWidget( mDisplayList[ row ][ column ], row, column ); + + if ( isVisible() ) { + mDisplayList[ row ][ column ]->show(); + } + + setMinimumSize(sizeHint()); + + setModified( true ); +} + +void WorkSheet::removeDisplay( KSGRD::SensorDisplay *display ) +{ + if ( !display ) + return; + + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + if ( mDisplayList[ r ][ c ] == display ) { + replaceDisplay( r, c ); + setModified( true ); + return; + } +} + +void WorkSheet::collectHosts( QStringList &list ) +{ + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + if ( !mDisplayList[ r ][ c ]->isA( "DummyDisplay" ) ) + ((KSGRD::SensorDisplay*)mDisplayList[ r ][ c ])->hosts( list ); +} + +void WorkSheet::createGrid( uint rows, uint columns ) +{ + mRows = rows; + mColumns = columns; + + // create grid layout with specified dimentions + mGridLayout = new QGridLayout( this, mRows, mColumns, 5 ); + + mDisplayList = new KSGRD::SensorDisplay**[ mRows ]; + for ( uint r = 0; r < mRows; ++r ) { + mDisplayList[ r ] = new KSGRD::SensorDisplay*[ mColumns ]; + for ( uint c = 0; c < mColumns; ++c ) + mDisplayList[ r ][ c ] = 0; + } + + /* set stretch factors for rows and columns */ + for ( uint r = 0; r < mRows; ++r ) + mGridLayout->setRowStretch( r, 100 ); + for ( uint c = 0; c < mColumns; ++c ) + mGridLayout->setColStretch( c, 100 ); +} + +void WorkSheet::resizeGrid( uint newRows, uint newColumns ) +{ + uint r, c; + + /* Create new array for display pointers */ + KSGRD::SensorDisplay*** newDisplayList = new KSGRD::SensorDisplay**[ newRows ]; + for ( r = 0; r < newRows; ++r ) { + newDisplayList[ r ] = new KSGRD::SensorDisplay*[ newColumns ]; + for ( c = 0; c < newColumns; ++c ) { + if ( c < mColumns && r < mRows ) + newDisplayList[ r ][ c ] = mDisplayList[ r ][ c ]; + else + newDisplayList[ r ][ c ] = 0; + } + } + + /* remove obsolete displays */ + for ( r = 0; r < mRows; ++r ) { + for ( c = 0; c < mColumns; ++c ) + if ( r >= newRows || c >= newColumns ) + delete mDisplayList[ r ][ c ]; + delete mDisplayList[ r ]; + } + delete [] mDisplayList; + + /* now we make the new display the regular one */ + mDisplayList = newDisplayList; + + /* create new displays */ + for ( r = 0; r < newRows; ++r ) + for ( c = 0; c < newColumns; ++c ) + if ( r >= mRows || c >= mColumns ) + replaceDisplay( r, c ); + + /* set stretch factors for new rows and columns (if any) */ + for ( r = mRows; r < newRows; ++r ) + mGridLayout->setRowStretch( r, 100 ); + for ( c = mColumns; c < newColumns; ++c ) + mGridLayout->setColStretch( c, 100 ); + + /* Obviously Qt does not shrink the size of the QGridLayout + * automatically. So we simply force the rows and columns that + * are no longer used to have a strech factor of 0 and hence be + * invisible. */ + for ( r = newRows; r < mRows; ++r ) + mGridLayout->setRowStretch( r, 0 ); + for ( c = newColumns; c < mColumns; ++c ) + mGridLayout->setColStretch( c, 0 ); + + mRows = newRows; + mColumns = newColumns; + + fixTabOrder(); + + mGridLayout->activate(); +} + +KSGRD::SensorDisplay *WorkSheet::display( uint row, uint column ) { + if(row >= mRows || column >= mColumns) return 0; + return mDisplayList[row][column]; +} +KSGRD::SensorDisplay *WorkSheet::currentDisplay( uint *row, uint *column ) +{ + for ( uint r = 0 ; r < mRows; ++r ) + for ( uint c = 0 ; c < mColumns; ++c ) + if ( mDisplayList[ r ][ c ]->hasFocus() ) { + if ( row ) + *row = r; + if ( column ) + *column = c; + return ( mDisplayList[ r ][ c ] ); + } + + return 0; +} + +void WorkSheet::fixTabOrder() +{ + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) { + if ( c + 1 < mColumns ) + setTabOrder( mDisplayList[ r ][ c ], mDisplayList[ r ][ c + 1 ] ); + else if ( r + 1 < mRows ) + setTabOrder( mDisplayList[ r ][ c ], mDisplayList[ r + 1 ][ 0 ] ); + } +} + +QString WorkSheet::currentDisplayAsXML() +{ + KSGRD::SensorDisplay* display = currentDisplay(); + if ( !display ) + return QString::null; + + /* We create an XML description of the current display. */ + QDomDocument doc( "KSysGuardDisplay" ); + doc.appendChild( doc.createProcessingInstruction( + "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); + + QDomElement element = doc.createElement( "display" ); + doc.appendChild( element ); + element.setAttribute( "class", display->className() ); + display->saveSettings( doc, element ); + + return doc.toString(); +} + +void WorkSheet::setIsOnTop( bool /* onTop */ ) +{ +/* + for ( uint r = 0; r < mRows; ++r ) + for ( uint c = 0; c < mColumns; ++c ) + mDisplayList[ r ][ c ]->setIsOnTop( onTop ); +*/ +} + +#include "WorkSheet.moc" diff --git a/ksysguard/gui/WorkSheet.h b/ksysguard/gui/WorkSheet.h new file mode 100644 index 000000000..f706f36dc --- /dev/null +++ b/ksysguard/gui/WorkSheet.h @@ -0,0 +1,135 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_WORKSHEET_H +#define KSG_WORKSHEET_H + +#include <qwidget.h> + +#include <SensorDisplay.h> + +class QDomElement; +class QDragEnterEvent; +class QDropEvent; +class QGridLayout; +class QString; +class QStringList; + +/** + A WorkSheet contains the displays to visualize the sensor results. When + creating the WorkSheet you must specify the number of columns. Displays + can be added and removed on the fly. The grid layout will handle the + layout. The number of columns can not be changed. Displays are added by + dragging a sensor from the sensor browser over the WorkSheet. + */ +class WorkSheet : public QWidget, public KSGRD::SensorBoard +{ + Q_OBJECT + + public: + WorkSheet( QWidget* parent, const char *name = 0 ); + WorkSheet( uint rows, uint columns, uint interval, QWidget* parent, + const char *name = 0 ); + ~WorkSheet(); + + bool load( const QString &fileName ); + bool save( const QString &fileName ); + + void cut(); + void copy(); + void paste(); + + void setFileName( const QString &fileName ); + const QString& fileName() const; + + bool modified() const; + + void setTitle( const QString &title ); + QString title() const; + + KSGRD::SensorDisplay* addDisplay( const QString &hostname, + const QString &monitor, + const QString &sensorType, + const QString &sensorDescr, + uint rows, uint columns ); + //Returns the sensor at position row,column. + //Return NULL if invalid row or column + KSGRD::SensorDisplay *display( uint row, uint column ); + + void settings(); + + void setIsOnTop( bool onTop ); + + public slots: + void showPopupMenu( KSGRD::SensorDisplay *display ); + void setModified( bool mfd ); + void applyStyle(); + + signals: + void sheetModified( QWidget *sheet ); + void titleChanged( QWidget *sheet ); + + protected: + virtual QSize sizeHint() const; + void dragEnterEvent( QDragEnterEvent* ); + void dropEvent( QDropEvent* ); + void customEvent( QCustomEvent* ); + + private: + void removeDisplay( KSGRD::SensorDisplay *display ); + + bool replaceDisplay( uint row, uint column, QDomElement& element ); + + void replaceDisplay( uint row, uint column, + KSGRD::SensorDisplay* display = 0 ); + + void collectHosts( QStringList &list ); + + void createGrid( uint rows, uint columns ); + + void resizeGrid( uint rows, uint columns ); + + KSGRD::SensorDisplay* currentDisplay( uint* row = 0, uint* column = 0 ); + + void fixTabOrder(); + + QString currentDisplayAsXML(); + + bool mModified; + + uint mRows; + uint mColumns; + + QGridLayout* mGridLayout; + QString mFileName; + QString mTitle; + + /** + This two dimensional array stores the pointers to the sensor displays + or if no sensor is present at a position a pointer to a dummy widget. + The size of the array corresponds to the size of the grid layout. + */ + KSGRD::SensorDisplay*** mDisplayList; +}; + +#endif diff --git a/ksysguard/gui/WorkSheetSettings.cc b/ksysguard/gui/WorkSheetSettings.cc new file mode 100644 index 000000000..e9ba0da08 --- /dev/null +++ b/ksysguard/gui/WorkSheetSettings.cc @@ -0,0 +1,153 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <kaccelmanager.h> +#include <klineedit.h> +#include <knuminput.h> +#include <klocale.h> + +#include <qgroupbox.h> +#include <qlabel.h> +#include <qspinbox.h> +#include <qlayout.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +#include "WorkSheetSettings.h" + +WorkSheetSettings::WorkSheetSettings( QWidget* parent, const char* name ) + : KDialogBase( parent, name, true, QString::null, Ok|Cancel, Ok, true ) +{ + setCaption( i18n( "Worksheet Properties" ) ); + + QWidget *page = new QWidget( this ); + setMainWidget( page ); + + QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + + QGroupBox *group = new QGroupBox( 0, Qt::Vertical, i18n( "Title" ), page ); + group->layout()->setMargin( marginHint() ); + group->layout()->setSpacing( spacingHint() ); + + QGridLayout *groupLayout = new QGridLayout( group->layout(), 1, 1 ); + groupLayout->setAlignment( Qt::AlignTop ); + + mSheetTitle = new KLineEdit( group ); + groupLayout->addWidget( mSheetTitle, 0, 0 ); + + topLayout->addWidget( group ); + + group = new QGroupBox( 0, Qt::Vertical, i18n( "Properties" ), page ); + group->layout()->setMargin( marginHint() ); + group->layout()->setSpacing( spacingHint() ); + + groupLayout = new QGridLayout( group->layout(), 3, 2 ); + groupLayout->setAlignment( Qt::AlignTop ); + + QLabel *label = new QLabel( i18n( "Rows:" ), group ); + groupLayout->addWidget( label, 0, 0 ); + + mRows = new KIntNumInput( 1, group ); + mRows->setMaxValue( 42 ); + mRows->setMinValue( 1 ); + groupLayout->addWidget( mRows, 0, 1 ); + label->setBuddy( mRows ); + + label = new QLabel( i18n( "Columns:" ), group ); + groupLayout->addWidget( label, 1, 0 ); + + mColumns = new KIntNumInput( 1, group ); + mColumns->setMaxValue( 42 ); + mColumns->setMinValue( 1 ); + groupLayout->addWidget( mColumns, 1, 1 ); + label->setBuddy( mColumns ); + + label = new QLabel( i18n( "Update interval:" ), group ); + groupLayout->addWidget( label, 2, 0 ); + + mInterval = new KIntNumInput( 2, group ); + mInterval->setMaxValue( 300 ); + mInterval->setMinValue( 1 ); + mInterval->setSuffix( i18n( " sec" ) ); + groupLayout->addWidget( mInterval, 2, 1 ); + label->setBuddy( mInterval ); + + topLayout->addWidget( group ); + + QWhatsThis::add( mRows, i18n( "Enter the number of rows the sheet should have." ) ); + QWhatsThis::add( mColumns, i18n( "Enter the number of columns the sheet should have." ) ); + QWhatsThis::add( mInterval, i18n( "All displays of the sheet are updated at the rate specified here." ) ); + QToolTip::add( mSheetTitle, i18n( "Enter the title of the worksheet here." ) ); + + KAcceleratorManager::manage( page ); + + mSheetTitle->setFocus(); + + resize( QSize( 250, 230 ).expandedTo( minimumSizeHint() ) ); +} + +WorkSheetSettings::~WorkSheetSettings() +{ +} + +void WorkSheetSettings::setRows( int rows ) +{ + mRows->setValue( rows ); +} + +int WorkSheetSettings::rows() const +{ + return mRows->value(); +} + +void WorkSheetSettings::setColumns( int columns ) +{ + mColumns->setValue( columns ); +} + +int WorkSheetSettings::columns() const +{ + return mColumns->value(); +} + +void WorkSheetSettings::setInterval( int interval ) +{ + mInterval->setValue( interval ); +} + +int WorkSheetSettings::interval() const +{ + return mInterval->value(); +} + +void WorkSheetSettings::setSheetTitle( const QString &title ) +{ + mSheetTitle->setText( title ); +} + +QString WorkSheetSettings::sheetTitle() const +{ + return mSheetTitle->text(); +} + +#include "WorkSheetSettings.moc" diff --git a/ksysguard/gui/WorkSheetSettings.h b/ksysguard/gui/WorkSheetSettings.h new file mode 100644 index 000000000..8fe5641a5 --- /dev/null +++ b/ksysguard/gui/WorkSheetSettings.h @@ -0,0 +1,60 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_WORKSHEETSETTINGS_H +#define KSG_WORKSHEETSETTINGS_H + +#include <kdialogbase.h> + +class KLineEdit; +class KIntNumInput; + +class WorkSheetSettings : public KDialogBase +{ + Q_OBJECT + + public: + WorkSheetSettings( QWidget* parent = 0, const char* name = 0 ); + ~WorkSheetSettings(); + + void setRows( int rows ); + int rows() const; + + void setColumns( int columns ); + int columns() const; + + void setInterval( int interval ); + int interval() const; + + void setSheetTitle( const QString &title ); + QString sheetTitle() const; + + private: + KLineEdit* mSheetTitle; + + KIntNumInput* mColumns; + KIntNumInput* mInterval; + KIntNumInput* mRows; +}; + +#endif diff --git a/ksysguard/gui/Workspace.cc b/ksysguard/gui/Workspace.cc new file mode 100644 index 000000000..c179317c0 --- /dev/null +++ b/ksysguard/gui/Workspace.cc @@ -0,0 +1,463 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2002 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <qlineedit.h> +#include <qspinbox.h> +#include <qwhatsthis.h> + +#include <kdebug.h> +#include <kfiledialog.h> +#include <kio/netaccess.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <kaccelmanager.h> + +#include "WorkSheet.h" +#include "WorkSheetSettings.h" +#include "ProcessController.h" + +#include "Workspace.h" + +Workspace::Workspace( QWidget* parent, const char* name ) + : QTabWidget( parent, name ) +{ + KAcceleratorManager::setNoAccel(this); + + mSheetList.setAutoDelete( true ); + mAutoSave = true; + + connect( this, SIGNAL( currentChanged( QWidget* ) ), + SLOT( updateCaption( QWidget* ) ) ); + + QWhatsThis::add( this, i18n( "This is your work space. It holds your worksheets. You need " + "to create a new worksheet (Menu File->New) before " + "you can drag sensors here." ) ); +} + +Workspace::~Workspace() +{ + /* This workaround is necessary to prevent a crash when the last + * page is not the current page. It seems like the the signal/slot + * administration data is already deleted but slots are still + * being triggered. TODO: I need to ask the Trolls about this. */ + + disconnect( this, SIGNAL( currentChanged( QWidget* ) ), this, + SLOT( updateCaption( QWidget* ) ) ); +} + +void Workspace::saveProperties( KConfig *cfg ) +{ + cfg->writePathEntry( "WorkDir", mWorkDir ); + cfg->writeEntry( "CurrentSheet", tabLabel( currentPage() ) ); + + QPtrListIterator<WorkSheet> it( mSheetList); + + QStringList list; + for ( int i = 0; it.current(); ++it, ++i ) + if ( !(*it)->fileName().isEmpty() ) + list.append( (*it)->fileName() ); + + cfg->writePathEntry( "Sheets", list ); +} + +void Workspace::readProperties( KConfig *cfg ) +{ + QString currentSheet; + + mWorkDir = cfg->readPathEntry( "WorkDir" ); + + if ( mWorkDir.isEmpty() ) { + /* If workDir is not specified in the config file, it's + * probably the first time the user has started KSysGuard. We + * then "restore" a special default configuration. */ + KStandardDirs* kstd = KGlobal::dirs(); + kstd->addResourceType( "data", "share/apps/ksysguard" ); + + mWorkDir = kstd->saveLocation( "data", "ksysguard" ); + + QString origFile = kstd->findResource( "data", "SystemLoad.sgrd" ); + QString newFile = mWorkDir + "/" + i18n( "System Load" ) + ".sgrd"; + if ( !origFile.isEmpty() ) + restoreWorkSheet( origFile, newFile ); + + origFile = kstd->findResource( "data", "ProcessTable.sgrd" ); + newFile = mWorkDir + "/" + i18n( "Process Table" ) + ".sgrd"; + if ( !origFile.isEmpty() ) + restoreWorkSheet( origFile, newFile ); + + currentSheet = i18n( "System Load" ); + } else { + currentSheet = cfg->readEntry( "CurrentSheet" ); + QStringList list = cfg->readPathListEntry( "Sheets" ); + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) + restoreWorkSheet( *it ); + } + + // Determine visible sheet. + QPtrListIterator<WorkSheet> it( mSheetList ); + for ( ; it.current(); ++it ) + if ( currentSheet == tabLabel(*it) ) { + showPage( *it ); + break; + } +} + +void Workspace::newWorkSheet() +{ + /* Find a name of the form "Sheet %d" that is not yet used by any + * of the existing worksheets. */ + QString sheetName; + bool found; + + int i = 1; + do { + sheetName = i18n( "Sheet %1" ).arg( i++ ); + QPtrListIterator<WorkSheet> it( mSheetList ); + found = false; + for ( ; it.current() && !found; ++it ) + if ( tabLabel(*it) == sheetName ) + found = true; + } while ( found ); + + WorkSheetSettings dlg( this ); + dlg.setSheetTitle( sheetName ); + if ( dlg.exec() ) { + WorkSheet* sheet = new WorkSheet( dlg.rows(), dlg.columns(), dlg.interval(), this ); + sheet->setTitle( dlg.sheetTitle() ); + insertTab( sheet, dlg.sheetTitle() ); + mSheetList.append( sheet ); + showPage( sheet ); + connect( sheet, SIGNAL( sheetModified( QWidget* ) ), + SLOT( updateCaption( QWidget* ) ) ); + connect( sheet, SIGNAL( titleChanged( QWidget* ) ), + SLOT( updateSheetTitle( QWidget* ) ) ); + } +} + +bool Workspace::saveOnQuit() +{ + QPtrListIterator<WorkSheet> it( mSheetList ); + for ( ; it.current(); ++it ) + if ( (*it)->modified() ) { + if ( !mAutoSave || (*it)->fileName().isEmpty() ) { + int res = KMessageBox::warningYesNoCancel( this, + i18n( "The worksheet '%1' contains unsaved data.\n" + "Do you want to save the worksheet?") + .arg( tabLabel( *it ) ), QString::null, KStdGuiItem::save(), KStdGuiItem::discard() ); + if ( res == KMessageBox::Yes ) + saveWorkSheet( *it ); + else if ( res == KMessageBox::Cancel ) + return false; // abort quit + } else + saveWorkSheet(*it); + } + + return true; +} + +void Workspace::loadWorkSheet() +{ + KFileDialog dlg( 0, i18n( "*.sgrd|Sensor Files" ), this, + "LoadFileDialog", true ); + + KURL url = dlg.getOpenURL( mWorkDir, "*.sgrd", 0, i18n( "Select Worksheet to Load" ) ); + + loadWorkSheet( url ); +} + +void Workspace::loadWorkSheet( const KURL &url ) +{ + if ( url.isEmpty() ) + return; + + /* It's probably not worth the effort to make this really network + * transparent. Unless s/o beats me up I use this pseudo transparent + * code. */ + QString tmpFile; + KIO::NetAccess::download( url, tmpFile, this ); + mWorkDir = tmpFile.left( tmpFile.findRev( '/' ) ); + + // Load sheet from file. + if ( !restoreWorkSheet( tmpFile ) ) + return; + + /* If we have loaded a non-local file we clear the file name so that + * the users is prompted for a new name for saving the file. */ + KURL tmpFileUrl; + tmpFileUrl.setPath( tmpFile ); + if ( tmpFileUrl != url.url() ) + mSheetList.last()->setFileName( QString::null ); + KIO::NetAccess::removeTempFile( tmpFile ); + + emit announceRecentURL( KURL( url ) ); +} + +void Workspace::saveWorkSheet() +{ + saveWorkSheet( (WorkSheet*)currentPage() ); +} + +void Workspace::saveWorkSheetAs() +{ + saveWorkSheetAs( (WorkSheet*)currentPage() ); +} + +void Workspace::saveWorkSheet( WorkSheet *sheet ) +{ + if ( !sheet ) { + KMessageBox::sorry( this, i18n( "You do not have a worksheet that could be saved." ) ); + return; + } + + QString fileName = sheet->fileName(); + if ( fileName.isEmpty() ) { + KFileDialog dlg( 0, i18n( "*.sgrd|Sensor Files" ), this, + "LoadFileDialog", true ); + fileName = dlg.getSaveFileName( mWorkDir + "/" + tabLabel( sheet ) + + ".sgrd", "*.sgrd", 0, + i18n( "Save Current Worksheet As" ) ); + if ( fileName.isEmpty() ) + return; + + mWorkDir = fileName.left( fileName.findRev( '/' ) ); + + // extract filename without path + QString baseName = fileName.right( fileName.length() - fileName.findRev( '/' ) - 1 ); + + // chop off extension (usually '.sgrd') + baseName = baseName.left( baseName.findRev( '.' ) ); + changeTab( sheet, baseName ); + } + + /* If we cannot save the file is probably write protected. So we need + * to ask the user for a new name. */ + if ( !sheet->save( fileName ) ) { + saveWorkSheetAs( sheet ); + return; + } + + /* Add file to recent documents menue. */ + KURL url; + url.setPath( fileName ); + emit announceRecentURL( url ); +} + +void Workspace::saveWorkSheetAs( WorkSheet *sheet ) +{ + if ( !sheet ) { + KMessageBox::sorry( this, i18n( "You do not have a worksheet that could be saved." ) ); + return; + } + + QString fileName; + do { + KFileDialog dlg( 0, "*.sgrd", this, "LoadFileDialog", true ); + fileName = dlg.getSaveFileName( mWorkDir + "/" + tabLabel( currentPage() ) + + ".sgrd", "*.sgrd" ); + if ( fileName.isEmpty() ) + return; + + mWorkDir = fileName.left( fileName.findRev( '/' ) ); + + // extract filename without path + QString baseName = fileName.right( fileName.length() - fileName.findRev( '/' ) - 1 ); + + // chop off extension (usually '.sgrd') + baseName = baseName.left( baseName.findRev( '.' ) ); + changeTab( sheet, baseName ); + } while ( !sheet->save( fileName ) ); + + /* Add file to recent documents menue. */ + KURL url; + url.setPath( fileName ); + emit announceRecentURL( url ); +} + +void Workspace::deleteWorkSheet() +{ + WorkSheet *current = (WorkSheet*)currentPage(); + + if ( current ) { + if ( current->modified() ) { + if ( !mAutoSave || current->fileName().isEmpty() ) { + int res = KMessageBox::warningYesNoCancel( this, + i18n( "The worksheet '%1' contains unsaved data.\n" + "Do you want to save the worksheet?" ) + .arg( tabLabel( current ) ), QString::null, KStdGuiItem::save(), KStdGuiItem::discard() ); + if ( res == KMessageBox::Cancel ) + return; + + if ( res == KMessageBox::Yes ) + saveWorkSheet( current ); + } else + saveWorkSheet( current ); + } + + removePage( current ); + mSheetList.remove( current ); + } else { + QString msg = i18n( "There are no worksheets that could be deleted." ); + KMessageBox::error( this, msg ); + } +} + +void Workspace::removeAllWorkSheets() +{ + WorkSheet *sheet; + while ( ( sheet = (WorkSheet*)currentPage() ) != 0 ) { + removePage( sheet ); + mSheetList.remove( sheet ); + } +} + +void Workspace::deleteWorkSheet( const QString &fileName ) +{ + QPtrListIterator<WorkSheet> it( mSheetList ); + for ( ; it.current(); ++it ) + if ( (*it)->fileName() == fileName ) { + removePage( *it ); + mSheetList.remove( *it ); + return; + } +} + +WorkSheet *Workspace::restoreWorkSheet( const QString &fileName, const QString &newName ) +{ + /* We might want to save the worksheet under a different name later. This + * name can be specified by newName. If newName is empty we use the + * original name to save the work sheet. */ + QString tmpStr; + if ( newName.isEmpty() ) + tmpStr = fileName; + else + tmpStr = newName; + + // extract filename without path + QString baseName = tmpStr.right( tmpStr.length() - tmpStr.findRev( '/' ) - 1 ); + + // chop off extension (usually '.sgrd') + baseName = baseName.left( baseName.findRev( '.' ) ); + + WorkSheet *sheet = new WorkSheet( this ); + sheet->setTitle( baseName ); + insertTab( sheet, baseName ); + showPage( sheet ); + + if ( !sheet->load( fileName ) ) { + delete sheet; + return NULL; + } + + mSheetList.append( sheet ); + connect( sheet, SIGNAL( sheetModified( QWidget* ) ), + SLOT( updateCaption( QWidget* ) ) ); + + /* Force the file name to be the new name. This also sets the modified + * flag, so that the file will get saved on exit. */ + if ( !newName.isEmpty() ) + sheet->setFileName( newName ); + + return sheet; +} + +void Workspace::cut() +{ + WorkSheet *current = (WorkSheet*)currentPage(); + + if ( current ) + current->cut(); +} + +void Workspace::copy() +{ + WorkSheet *current = (WorkSheet*)currentPage(); + + if ( current ) + current->copy(); +} + +void Workspace::paste() +{ + WorkSheet *current = (WorkSheet*)currentPage(); + + if ( current ) + current->paste(); +} + +void Workspace::configure() +{ + WorkSheet *current = (WorkSheet*)currentPage(); + + if ( !current ) + return; + + current->settings(); +} + +void Workspace::updateCaption( QWidget* wdg ) +{ + if ( wdg ) + emit setCaption( tabLabel( wdg ), ((WorkSheet*)wdg)->modified() ); + else + emit setCaption( QString::null, false ); + + for ( WorkSheet* s = mSheetList.first(); s != 0; s = mSheetList.next() ) + ((WorkSheet*)s)->setIsOnTop( s == wdg ); +} + +void Workspace::updateSheetTitle( QWidget* wdg ) +{ + if ( wdg ) + changeTab( wdg, static_cast<WorkSheet*>( wdg )->title() ); +} + +void Workspace::applyStyle() +{ + if ( currentPage() ) + ((WorkSheet*)currentPage())->applyStyle(); +} + +void Workspace::showProcesses() +{ + KStandardDirs* kstd = KGlobal::dirs(); + kstd->addResourceType( "data", "share/apps/ksysguard" ); + + QString file = kstd->findResource( "data", "ProcessTable.sgrd" ); + if ( file.isEmpty() ) { + KMessageBox::error( this, i18n( "Cannot find file ProcessTable.sgrd." ) ); + return; + } + WorkSheet *processSheet = restoreWorkSheet( file ); + if(!processSheet) return; + + //Set the focus of the search line. This is nasty I know, but I don't know how better to do this :( + KSGRD::SensorDisplay *processSensor = processSheet->display( 0,0 ); + if(!processSensor || !processSensor->isA("ProcessController")) return; + ProcessController *controller = dynamic_cast<ProcessController *>(processSensor); + if(!controller) return; + controller->setSearchFocus(); + +} + +#include "Workspace.moc" diff --git a/ksysguard/gui/Workspace.h b/ksysguard/gui/Workspace.h new file mode 100644 index 000000000..af27f6303 --- /dev/null +++ b/ksysguard/gui/Workspace.h @@ -0,0 +1,84 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_WORKSPACE_H +#define KSG_WORKSPACE_H + +#include <qptrlist.h> +#include <qtabwidget.h> + +class KConfig; +class KURL; +class QString; +class WorkSheet; + +class Workspace : public QTabWidget +{ + Q_OBJECT + + public: + Workspace( QWidget* parent, const char* name = 0 ); + ~Workspace(); + + void saveProperties( KConfig* ); + void readProperties( KConfig* ); + + bool saveOnQuit(); + + void showProcesses(); + + WorkSheet *restoreWorkSheet( const QString &fileName, + const QString &newName = QString::null ); + void deleteWorkSheet( const QString &fileName ); + + public slots: + void newWorkSheet(); + void loadWorkSheet(); + void loadWorkSheet( const KURL& ); + void saveWorkSheet(); + void saveWorkSheet( WorkSheet *sheet ); + void saveWorkSheetAs(); + void saveWorkSheetAs( WorkSheet *sheet ); + void deleteWorkSheet(); + void removeAllWorkSheets(); + void cut(); + void copy(); + void paste(); + void configure(); + void updateCaption( QWidget* ); + void updateSheetTitle( QWidget* ); + void applyStyle(); + + signals: + void announceRecentURL( const KURL &url ); + void setCaption( const QString &text, bool modified ); + + private: + QPtrList<WorkSheet> mSheetList; + + // Directory that was used for the last load/save. + QString mWorkDir; + bool mAutoSave; +}; + +#endif diff --git a/ksysguard/gui/kpm.c b/ksysguard/gui/kpm.c new file mode 100644 index 000000000..5ce25516a --- /dev/null +++ b/ksysguard/gui/kpm.c @@ -0,0 +1,8 @@ +/* A small wrapper to call ksysguard --showprocesses */ + +#include <unistd.h> + +int main() +{ + return execlp( "ksysguard", "ksysguard", "--showprocesses", 0 ); +} diff --git a/ksysguard/gui/ksgrd/HostConnector.cc b/ksysguard/gui/ksgrd/HostConnector.cc new file mode 100644 index 000000000..5762d08b3 --- /dev/null +++ b/ksysguard/gui/ksgrd/HostConnector.cc @@ -0,0 +1,217 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <kapplication.h> +#include <kaccelmanager.h> +#include <kcombobox.h> +#include <klocale.h> + +#include <qbuttongroup.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qradiobutton.h> +#include <qspinbox.h> +#include <qtooltip.h> +#include <qwhatsthis.h> + +#include "HostConnector.h" + +HostConnector::HostConnector( QWidget *parent, const char *name ) + : KDialogBase( Plain, i18n( "Connect Host" ), Help | Ok | Cancel, Ok, + parent, name, true, true ) +{ + QFrame *page = plainPage(); + QGridLayout *layout = new QGridLayout( page, 2, 2, 0, spacingHint() ); + layout->setColStretch( 1, 1 ); + + QLabel *label = new QLabel( i18n( "Host:" ), page ); + layout->addWidget( label, 0, 0 ); + + mHostNames = new KComboBox( true, page ); + mHostNames->setMaxCount( 20 ); + mHostNames->setInsertionPolicy( QComboBox::AtTop ); + mHostNames->setAutoCompletion( true ); + mHostNames->setDuplicatesEnabled( false ); + layout->addWidget( mHostNames, 0, 1 ); + label->setBuddy( mHostNames ); + QWhatsThis::add( mHostNames, i18n( "Enter the name of the host you want to connect to." ) ); + + mHostNameLabel = new QLabel( page ); + mHostNameLabel->hide(); + layout->addWidget( mHostNameLabel, 0, 1 ); + + QButtonGroup *group = new QButtonGroup( 0, Qt::Vertical, + i18n( "Connection Type" ), page ); + QGridLayout *groupLayout = new QGridLayout( group->layout(), 4, 4, + spacingHint() ); + groupLayout->setAlignment( Qt::AlignTop ); + + mUseSsh = new QRadioButton( i18n( "ssh" ), group ); + mUseSsh->setEnabled( true ); + mUseSsh->setChecked( true ); + QWhatsThis::add( mUseSsh, i18n( "Select this to use the secure shell to login to the remote host." ) ); + groupLayout->addWidget( mUseSsh, 0, 0 ); + + mUseRsh = new QRadioButton( i18n( "rsh" ), group ); + QWhatsThis::add( mUseRsh, i18n( "Select this to use the remote shell to login to the remote host." ) ); + groupLayout->addWidget( mUseRsh, 0, 1 ); + + mUseDaemon = new QRadioButton( i18n( "Daemon" ), group ); + QWhatsThis::add( mUseDaemon, i18n( "Select this if you want to connect to a ksysguard daemon that is running on the machine you want to connect to, and is listening for client requests." ) ); + groupLayout->addWidget( mUseDaemon, 0, 2 ); + + mUseCustom = new QRadioButton( i18n( "Custom command" ), group ); + QWhatsThis::add( mUseCustom, i18n( "Select this to use the command you entered below to start ksysguardd on the remote host." ) ); + groupLayout->addWidget( mUseCustom, 0, 3 ); + + label = new QLabel( i18n( "Port:" ), group ); + groupLayout->addWidget( label, 1, 0 ); + + mPort = new QSpinBox( 1, 65535, 1, group ); + mPort->setEnabled( false ); + mPort->setValue( 3112 ); + QToolTip::add( mPort, i18n( "Enter the port number on which the ksysguard daemon is listening for connections." ) ); + groupLayout->addWidget( mPort, 1, 2 ); + + label = new QLabel( i18n( "e.g. 3112" ), group ); + groupLayout->addWidget( label, 1, 3 ); + + label = new QLabel( i18n( "Command:" ), group ); + groupLayout->addWidget( label, 2, 0 ); + + mCommands = new KComboBox( true, group ); + mCommands->setEnabled( false ); + mCommands->setMaxCount( 20 ); + mCommands->setInsertionPolicy( QComboBox::AtTop ); + mCommands->setAutoCompletion( true ); + mCommands->setDuplicatesEnabled( false ); + QWhatsThis::add( mCommands, i18n( "Enter the command that runs ksysguardd on the host you want to monitor." ) ); + groupLayout->addMultiCellWidget( mCommands, 2, 2, 2, 3 ); + label->setBuddy( mCommands ); + + label = new QLabel( i18n( "e.g. ssh -l root remote.host.org ksysguardd" ), group ); + groupLayout->addMultiCellWidget( label, 3, 3, 2, 3 ); + + layout->addMultiCellWidget( group, 1, 1, 0, 1 ); + + connect( mUseCustom, SIGNAL( toggled( bool ) ), + mCommands, SLOT( setEnabled( bool ) ) ); + connect( mUseDaemon, SIGNAL( toggled( bool ) ), + mPort, SLOT( setEnabled( bool ) ) ); + connect( mHostNames->lineEdit(), SIGNAL( textChanged ( const QString & ) ), + this, SLOT( slotHostNameChanged( const QString & ) ) ); + enableButtonOK( !mHostNames->lineEdit()->text().isEmpty() ); + KAcceleratorManager::manage( this ); +} + +HostConnector::~HostConnector() +{ +} + +void HostConnector::slotHostNameChanged( const QString &_text ) +{ + enableButtonOK( !_text.isEmpty() ); +} + +void HostConnector::setHostNames( const QStringList &list ) +{ + mHostNames->insertStringList( list ); +} + +QStringList HostConnector::hostNames() const +{ + QStringList list; + + for ( int i = 0; i < mHostNames->count(); ++i ) + list.append( mHostNames->text( i ) ); + + return list; +} + +void HostConnector::setCommands( const QStringList &list ) +{ + mCommands->insertStringList( list ); +} + +QStringList HostConnector::commands() const +{ + QStringList list; + + for ( int i = 0; i < mCommands->count(); ++i ) + list.append( mCommands->text( i ) ); + + return list; +} + +void HostConnector::setCurrentHostName( const QString &hostName ) +{ + if ( !hostName.isEmpty() ) { + mHostNames->hide(); + mHostNameLabel->setText( hostName ); + mHostNameLabel->show(); + enableButtonOK( true );//enable true when mHostNames is empty and hidden fix #66955 + } else { + mHostNameLabel->hide(); + mHostNames->show(); + mHostNames->setFocus(); + } +} + +QString HostConnector::currentHostName() const +{ + return mHostNames->currentText(); +} + +QString HostConnector::currentCommand() const +{ + return mCommands->currentText(); +} + +int HostConnector::port() const +{ + return mPort->value(); +} + +bool HostConnector::useSsh() const +{ + return mUseSsh->isChecked(); +} + +bool HostConnector::useRsh() const +{ + return mUseRsh->isChecked(); +} + +bool HostConnector::useDaemon() const +{ + return mUseDaemon->isChecked(); +} + +bool HostConnector::useCustom() const +{ + return mUseCustom->isChecked(); +} + +void HostConnector::slotHelp() +{ + kapp->invokeHelp( "CONNECTINGTOOTHERHOSTS", "ksysguard/the-sensor-browser.html" ); +} + +#include "HostConnector.moc" diff --git a/ksysguard/gui/ksgrd/HostConnector.h b/ksysguard/gui/ksgrd/HostConnector.h new file mode 100644 index 000000000..eadf728cd --- /dev/null +++ b/ksysguard/gui/ksgrd/HostConnector.h @@ -0,0 +1,74 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_HOSTCONNECTOR_H +#define KSG_HOSTCONNECTOR_H + +#include <kdialogbase.h> + +class KComboBox; + +class QLabel; +class QRadioButton; +class QSpinBox; + +class HostConnector : public KDialogBase +{ + Q_OBJECT + + public: + HostConnector( QWidget *parent, const char *name = 0 ); + ~HostConnector(); + + void setHostNames( const QStringList &list ); + QStringList hostNames() const; + + void setCommands( const QStringList &list ); + QStringList commands() const; + + void setCurrentHostName( const QString &hostName ); + + QString currentHostName() const; + QString currentCommand() const; + int port() const; + + bool useSsh() const; + bool useRsh() const; + bool useDaemon() const; + bool useCustom() const; + + protected slots: + virtual void slotHelp(); + void slotHostNameChanged( const QString &_text ); + private: + KComboBox *mCommands; + KComboBox *mHostNames; + + QLabel *mHostNameLabel; + + QRadioButton *mUseSsh; + QRadioButton *mUseRsh; + QRadioButton *mUseDaemon; + QRadioButton *mUseCustom; + + QSpinBox *mPort; +}; + +#endif diff --git a/ksysguard/gui/ksgrd/Makefile.am b/ksysguard/gui/ksgrd/Makefile.am new file mode 100644 index 000000000..ff5f0aa47 --- /dev/null +++ b/ksysguard/gui/ksgrd/Makefile.am @@ -0,0 +1,34 @@ + +# set the include path for X, qt and KDE +INCLUDES= -I$(srcdir)/../SensorDisplayLib $(all_includes) + +lib_LTLIBRARIES = libksgrd.la + +libksgrd_la_LDFLAGS = -no-undefined -version-info 3:0:2 $(all_libraries) +libksgrd_la_LIBADD = $(LIB_KDEUI) + +# Which sources should be compiled for ksysguard. +libksgrd_la_SOURCES = \ + HostConnector.cc \ + SensorAgent.cc \ + SensorManager.cc \ + SensorShellAgent.cc \ + SensorSocketAgent.cc \ + StyleEngine.cc \ + StyleSettings.cc \ + TimerSettings.cc + +ksgrdincludedir = $(includedir)/ksgrd +ksgrdinclude_HEADERS = \ + HostConnector.h \ + SensorAgent.h \ + SensorClient.h \ + SensorManager.h \ + SensorShellAgent.h \ + SensorSocketAgent.h \ + StyleEngine.h \ + StyleSettings.h \ + TimerSettings.h + +# just to make sure, automake makes them +libksgrd_la_METASOURCES = AUTO diff --git a/ksysguard/gui/ksgrd/SensorAgent.cc b/ksysguard/gui/ksgrd/SensorAgent.cc new file mode 100644 index 000000000..a24bf5594 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorAgent.cc @@ -0,0 +1,260 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdlib.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kpassdlg.h> + +#include "SensorClient.h" +#include "SensorManager.h" + +#include "SensorAgent.h" + +/** + This can be used to debug communication problems with the daemon. + Should be set to 0 in any production version. +*/ +#define SA_TRACE 0 + +using namespace KSGRD; + +SensorAgent::SensorAgent( SensorManager *sm ) + : mSensorManager( sm ) +{ + /* SensorRequests migrate from the inputFIFO to the processingFIFO. So + * we only have to delete them when they are removed from the + * processingFIFO. */ + mInputFIFO.setAutoDelete( false ); + mProcessingFIFO.setAutoDelete( true ); + + mDaemonOnLine = false; + mTransmitting = false; + mState = 0; +} + +SensorAgent::~SensorAgent() +{ +} + +bool SensorAgent::sendRequest( const QString &req, SensorClient *client, int id ) +{ + /* The request is registered with the FIFO so that the answer can be + * routed back to the requesting client. */ + mInputFIFO.prepend( new SensorRequest( req, client, id ) ); + +#if SA_TRACE + kdDebug(1215) << "-> " << req << "(" << mInputFIFO.count() << "/" + << mProcessingFIFO.count() << ")" << endl; +#endif + executeCommand(); + + return false; +} + +void SensorAgent::processAnswer( const QString &buffer ) +{ +#if SA_TRACE + kdDebug(1215) << "<- " << buffer << endl; +#endif + + for ( uint i = 0; i < buffer.length(); i++ ) { + if ( buffer[ i ] == '\033' ) { + mState = ( mState + 1 ) & 1; + if ( !mErrorBuffer.isEmpty() && mState == 0 ) { + if ( mErrorBuffer == "RECONFIGURE\n" ) + emit reconfigure( this ); + else { + /* We just received the end of an error message, so we + * can display it. */ + SensorMgr->notify( i18n( "Message from %1:\n%2" ) + .arg( mHostName ) + .arg( mErrorBuffer ) ); + } + mErrorBuffer = QString::null; + } + } else if ( mState == 0 ) // receiving to answerBuffer + mAnswerBuffer += buffer[ i ]; + else // receiving to errorBuffer + mErrorBuffer += buffer[ i ]; + } + + int end; + // And now the real information + while ( ( end = mAnswerBuffer.find( "\nksysguardd> " ) ) >= 0 ) { +#if SA_TRACE + kdDebug(1215) << "<= " << mAnswerBuffer.left( end ) + << "(" << mInputFIFO.count() << "/" + << mProcessingFIFO.count() << ")" << endl; +#endif + if ( !mDaemonOnLine ) { + /* First '\nksysguardd> ' signals that the daemon is + * ready to serve requests now. */ + mDaemonOnLine = true; +#if SA_TRACE + kdDebug(1215) << "Daemon now online!" << endl; +#endif + mAnswerBuffer = QString::null; + break; + } + + // remove pending request from FIFO + SensorRequest* req = mProcessingFIFO.last(); + if ( !req ) { + kdDebug(1215) << "ERROR: Received answer but have no pending " + << "request! : " << mAnswerBuffer.left( end ) << endl; + mAnswerBuffer = QString::null; + } else { + if ( !req->client() ) { + /* The client has disappeared before receiving the answer + * to his request. */ + } else { + if ( mAnswerBuffer.left( end ) == "UNKNOWN COMMAND" ) { + /* Notify client that the sensor seems to be no longer + * available. */ + req->client()->sensorLost( req->id() ); + } else { + // Notify client of newly arrived answer. + req->client()->answerReceived( req->id(), mAnswerBuffer.left( end ) ); + } + } + mProcessingFIFO.removeLast(); + } + // chop off the processed part of the answer buffer + mAnswerBuffer.remove( 0, end + strlen( "\nksysguardd> " ) ); + } + + executeCommand(); +} + +void SensorAgent::executeCommand() +{ + /* This function is called whenever there is a chance that we have a + * command to pass to the daemon. But the command many only be send + * if the daemon is online and there is no other command currently + * being sent. */ + if ( mDaemonOnLine && txReady() && !mInputFIFO.isEmpty() ) { + // take oldest request for input FIFO + SensorRequest* req = mInputFIFO.last(); + mInputFIFO.removeLast(); + +#if SA_TRACE + kdDebug(1215) << ">> " << req->request().ascii() << "(" << mInputFIFO.count() + << "/" << mProcessingFIFO.count() << ")" << endl; +#endif + // send request to daemon + QString cmdWithNL = req->request() + "\n"; + if ( writeMsg( cmdWithNL.ascii(), cmdWithNL.length() ) ) + mTransmitting = true; + else + kdDebug(1215) << "SensorAgent::writeMsg() failed" << endl; + + // add request to processing FIFO + mProcessingFIFO.prepend( req ); + } +} + +void SensorAgent::disconnectClient( SensorClient *client ) +{ + for ( SensorRequest *req = mInputFIFO.first(); req; req = mInputFIFO.next() ) + if ( req->client() == client ) + req->setClient( 0 ); + for ( SensorRequest *req = mProcessingFIFO.first(); req; req = mProcessingFIFO.next() ) + if ( req->client() == client ) + req->setClient( 0 ); +} + +SensorManager *SensorAgent::sensorManager() +{ + return mSensorManager; +} + +void SensorAgent::setDaemonOnLine( bool value ) +{ + mDaemonOnLine = value; +} + +bool SensorAgent::daemonOnLine() const +{ + return mDaemonOnLine; +} + +void SensorAgent::setTransmitting( bool value ) +{ + mTransmitting = value; +} + +bool SensorAgent::transmitting() const +{ + return mTransmitting; +} + +void SensorAgent::setHostName( const QString &hostName ) +{ + mHostName = hostName; +} + +const QString &SensorAgent::hostName() const +{ + return mHostName; +} + + +SensorRequest::SensorRequest( const QString &request, SensorClient *client, int id ) + : mRequest( request ), mClient( client ), mId( id ) +{ +} + +SensorRequest::~SensorRequest() +{ +} + +void SensorRequest::setRequest( const QString &request ) +{ + mRequest = request; +} + +QString SensorRequest::request() const +{ + return mRequest; +} + +void SensorRequest::setClient( SensorClient *client ) +{ + mClient = client; +} + +SensorClient *SensorRequest::client() +{ + return mClient; +} + +void SensorRequest::setId( int id ) +{ + mId = id; +} + +int SensorRequest::id() +{ + return mId; +} + +#include "SensorAgent.moc" diff --git a/ksysguard/gui/ksgrd/SensorAgent.h b/ksysguard/gui/ksgrd/SensorAgent.h new file mode 100644 index 000000000..e30deb510 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorAgent.h @@ -0,0 +1,137 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_SENSORAGENT_H +#define KSG_SENSORAGENT_H + +#include <qobject.h> +#include <qptrlist.h> + +class KProcess; +class KShellProcess; + +class QString; + +namespace KSGRD { + +class SensorClient; +class SensorManager; +class SensorRequest; + +/** + The SensorAgent depending on the type of requested connection + starts a ksysguardd process or connects through a tcp connection to + a running ksysguardd and handles the asynchronous communication. It + keeps a list of pending requests that have not been answered yet by + ksysguardd. The current implementation only allowes one pending + requests. Incoming requests are queued in an input FIFO. +*/ +class KDE_EXPORT SensorAgent : public QObject +{ + Q_OBJECT + + public: + SensorAgent( SensorManager *sm ); + virtual ~SensorAgent(); + + virtual bool start( const QString &host, const QString &shell, + const QString &command = "", int port = -1 ) = 0; + + /** + This function should only be used by the the SensorManager and + never by the SensorClients directly since the pointer returned by + engaged is not guaranteed to be valid. Only the SensorManager knows + whether a SensorAgent pointer is still valid or not. + + This function sends out a command to the sensor and notifies the + agent to return the answer to 'client'. The 'id' can be used by the + client to identify the answer. It is only passed through and never + used by the SensorAgent. So it can be any value the client suits to + use. + */ + bool sendRequest( const QString &req, SensorClient *client, int id = 0 ); + + virtual void hostInfo( QString &sh, QString &cmd, int &port ) const = 0; + + void disconnectClient( SensorClient *client ); + + const QString &hostName() const; + + signals: + void reconfigure( const SensorAgent* ); + + protected: + void processAnswer( const QString &buffer ); + void executeCommand(); + + SensorManager *sensorManager(); + + void setDaemonOnLine( bool value ); + bool daemonOnLine() const; + + void setTransmitting( bool value ); + bool transmitting() const; + + void setHostName( const QString &hostName ); + + private: + virtual bool writeMsg( const char *msg, int len ) = 0; + virtual bool txReady() = 0; + + int mState; + QPtrList<SensorRequest> mInputFIFO; + QPtrList<SensorRequest> mProcessingFIFO; + QString mAnswerBuffer; + QString mErrorBuffer; + + SensorManager *mSensorManager; + + bool mDaemonOnLine; + bool mTransmitting; + QString mHostName; +}; + +/** + This auxilliary class is used to store requests during their processing. +*/ +class SensorRequest +{ + public: + SensorRequest( const QString &request, SensorClient *client, int id ); + ~SensorRequest(); + + void setRequest( const QString& ); + QString request() const; + + void setClient( SensorClient* ); + SensorClient *client(); + + void setId( int ); + int id(); + + private: + QString mRequest; + SensorClient *mClient; + int mId; +}; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/SensorClient.h b/ksysguard/gui/ksgrd/SensorClient.h new file mode 100644 index 000000000..30586a8a2 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorClient.h @@ -0,0 +1,209 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_SENSORCLIENT_H +#define KSG_SENSORCLIENT_H + +#include <qptrlist.h> +#include <qstring.h> + +namespace KSGRD { + +/** + Every object that should act as a client to a sensor must inherit from + this class. A pointer to the client object is passed as SensorClient* + to the SensorAgent. When the requested information is available or a + problem occurred one of the member functions is called. + */ +class SensorClient +{ + public: + SensorClient() { } + virtual ~SensorClient() { } + + /** + This function is called whenever the information form the sensor has + been received by the sensor agent. This function must be reimplemented + by the sensor client to receive and process this information. + */ + virtual void answerReceived( int, const QString& ) { } + + /** + In case of an unexpected fatal problem with the sensor the sensor + agent will call this function to notify the client about it. + */ + virtual void sensorLost( int ) { } +}; + +/** + Every object that has a SensorClient as a child must inherit from + this class to support the advanced update interval settings. + */ +class SensorBoard +{ + public: + SensorBoard() { } + virtual ~SensorBoard() { } + + void updateInterval( int interval ) { mUpdateInterval = interval; } + + int updateInterval() { return mUpdateInterval; } + + private: + int mUpdateInterval; +}; + +/** + The following classes are utility classes that provide a + convenient way to retrieve pieces of information from the sensor + answers. For each type of answer there is a separate class. + */ +class SensorTokenizer +{ + public: + SensorTokenizer( const QString &info, QChar separator ) + { + mTokens = QStringList::split( separator, info ); + } + + ~SensorTokenizer() { } + + const QString& operator[]( unsigned idx ) + { + return mTokens[ idx ]; + } + + uint count() + { + return mTokens.count(); + } + + private: + QStringList mTokens; +}; + +/** + An integer info contains 4 fields seperated by TABS, a description + (name), the minimum and the maximum values and the unit. + e.g. Swap Memory 0 133885952 KB + */ +class SensorIntegerInfo : public SensorTokenizer +{ + public: + SensorIntegerInfo( const QString &info ) + : SensorTokenizer( info, '\t' ) { } + + ~SensorIntegerInfo() { } + + const QString &name() + { + return (*this)[ 0 ]; + } + + long min() + { + return (*this)[ 1 ].toLong(); + } + + long max() + { + return (*this)[ 2 ].toLong(); + } + + const QString &unit() + { + return (*this)[ 3 ]; + } +}; + +/** + An float info contains 4 fields seperated by TABS, a description + (name), the minimum and the maximum values and the unit. + e.g. CPU Voltage 0.0 5.0 V + */ +class SensorFloatInfo : public SensorTokenizer +{ + public: + SensorFloatInfo( const QString &info ) + : SensorTokenizer( info, '\t' ) { } + + ~SensorFloatInfo() { } + + const QString &name() + { + return (*this)[ 0 ]; + } + + double min() + { + return (*this)[ 1 ].toDouble(); + } + + double max() + { + return (*this)[ 2 ].toDouble(); + } + + const QString &unit() + { + return (*this)[ 3 ]; + } +}; + +/** + A PS line consists of information about a process. Each piece of + information is seperated by a TAB. The first 4 fields are process name, + PID, PPID and real user ID. Those fields are mandatory. + */ +class SensorPSLine : public SensorTokenizer +{ + public: + SensorPSLine( const QString &line ) + : SensorTokenizer( line, '\t' ) { } + + ~SensorPSLine() { } + + const QString& name() + { + return (*this)[ 0 ]; + } + + long pid() + { + return (*this)[ 1 ].toLong(); + } + + long ppid() + { + return (*this)[ 2 ].toLong(); + } + + long uid() + { + return (*this)[ 3 ].toLong(); + } +}; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/SensorManager.cc b/ksysguard/gui/ksgrd/SensorManager.cc new file mode 100644 index 000000000..065da717a --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorManager.cc @@ -0,0 +1,432 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <qcombobox.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <qspinbox.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <klocale.h> + +#include "HostConnector.h" +#include "SensorShellAgent.h" +#include "SensorSocketAgent.h" + +#include "SensorManager.h" + +using namespace KSGRD; + +SensorManager* KSGRD::SensorMgr; + +SensorManager::SensorManager() +{ + mAgents.setAutoDelete( true ); + mDict.setAutoDelete( true ); + + // Fill the sensor description dictionary. + mDict.insert( "cpu", new QString( i18n( "CPU Load" ) ) ); + mDict.insert( "idle", new QString( i18n( "Idle Load" ) ) ); + mDict.insert( "sys", new QString( i18n( "System Load" ) ) ); + mDict.insert( "nice", new QString( i18n( "Nice Load" ) ) ); + mDict.insert( "user", new QString( i18n( "User Load" ) ) ); + mDict.insert( "mem", new QString( i18n( "Memory" ) ) ); + mDict.insert( "physical", new QString( i18n( "Physical Memory" ) ) ); + mDict.insert( "swap", new QString( i18n( "Swap Memory" ) ) ); + mDict.insert( "cached", new QString( i18n( "Cached Memory" ) ) ); + mDict.insert( "buf", new QString( i18n( "Buffered Memory" ) ) ); + mDict.insert( "used", new QString( i18n( "Used Memory" ) ) ); + mDict.insert( "application", new QString( i18n( "Application Memory" ) ) ); + mDict.insert( "free", new QString( i18n( "Free Memory" ) ) ); + mDict.insert( "pscount", new QString( i18n( "Process Count" ) ) ); + mDict.insert( "ps", new QString( i18n( "Process Controller" ) ) ); + mDict.insert( "disk", new QString( i18n( "Disk Throughput" ) ) ); + mDict.insert( "load", new QString( i18n( "CPU Load", "Load" ) ) ); + mDict.insert( "total", new QString( i18n( "Total Accesses" ) ) ); + mDict.insert( "rio", new QString( i18n( "Read Accesses" ) ) ); + mDict.insert( "wio", new QString( i18n( "Write Accesses" ) ) ); + mDict.insert( "rblk", new QString( i18n( "Read Data" ) ) ); + mDict.insert( "wblk", new QString( i18n( "Write Data" ) ) ); + mDict.insert( "pageIn", new QString( i18n( "Pages In" ) ) ); + mDict.insert( "pageOut", new QString( i18n( "Pages Out" ) ) ); + mDict.insert( "context", new QString( i18n( "Context Switches" ) ) ); + mDict.insert( "network", new QString( i18n( "Network" ) ) ); + mDict.insert( "interfaces", new QString( i18n( "Interfaces" ) ) ); + mDict.insert( "receiver", new QString( i18n( "Receiver" ) ) ); + mDict.insert( "transmitter", new QString( i18n( "Transmitter" ) ) ); + mDict.insert( "data", new QString( i18n( "Data" ) ) ); + mDict.insert( "compressed", new QString( i18n( "Compressed Packets" ) ) ); + mDict.insert( "drops", new QString( i18n( "Dropped Packets" ) ) ); + mDict.insert( "errors", new QString( i18n( "Errors" ) ) ); + mDict.insert( "fifo", new QString( i18n( "FIFO Overruns" ) ) ); + mDict.insert( "frame", new QString( i18n( "Frame Errors" ) ) ); + mDict.insert( "multicast", new QString( i18n( "Multicast" ) ) ); + mDict.insert( "packets", new QString( i18n( "Packets" ) ) ); + mDict.insert( "carrier", new QString( i18n( "Carrier" ) ) ); + mDict.insert( "collisions", new QString( i18n( "Collisions" ) ) ); + mDict.insert( "sockets", new QString( i18n( "Sockets" ) ) ); + mDict.insert( "count", new QString( i18n( "Total Number" ) ) ); + mDict.insert( "list", new QString( i18n( "Table" ) ) ); + mDict.insert( "apm", new QString( i18n( "Advanced Power Management" ) ) ); + mDict.insert( "acpi", new QString( i18n( "ACPI" ) ) ); + mDict.insert( "thermal_zone", new QString( i18n( "Thermal Zone" ) ) ); + mDict.insert( "temperature", new QString( i18n( "Temperature" ) ) ); + mDict.insert( "fan", new QString( i18n( "Fan" ) ) ); + mDict.insert( "state", new QString( i18n( "State" ) ) ); + mDict.insert( "battery", new QString( i18n( "Battery" ) ) ); + mDict.insert( "batterycharge", new QString( i18n( "Battery Charge" ) ) ); + mDict.insert( "batteryusage", new QString( i18n( "Battery Usage" ) ) ); + mDict.insert( "remainingtime", new QString( i18n( "Remaining Time" ) ) ); + mDict.insert( "interrupts", new QString( i18n( "Interrupts" ) ) ); + mDict.insert( "loadavg1", new QString( i18n( "Load Average (1 min)" ) ) ); + mDict.insert( "loadavg5", new QString( i18n( "Load Average (5 min)" ) ) ); + mDict.insert( "loadavg15", new QString( i18n( "Load Average (15 min)" ) ) ); + mDict.insert( "clock", new QString( i18n( "Clock Frequency" ) ) ); + mDict.insert( "lmsensors", new QString( i18n( "Hardware Sensors" ) ) ); + mDict.insert( "partitions", new QString( i18n( "Partition Usage" ) ) ); + mDict.insert( "usedspace", new QString( i18n( "Used Space" ) ) ); + mDict.insert( "freespace", new QString( i18n( "Free Space" ) ) ); + mDict.insert( "filllevel", new QString( i18n( "Fill Level" ) ) ); + + for ( int i = 0; i < 32; i++ ) { + mDict.insert( "cpu" + QString::number( i ), + new QString( QString( i18n( "CPU%1" ) ).arg( i ) ) ); + mDict.insert( "disk" + QString::number( i ), + new QString( QString( i18n( "Disk%1" ) ).arg( i ) ) ); + } + + for ( int i = 0; i < 6; i++) { + mDict.insert( "fan" + QString::number( i ), + new QString( QString( i18n( "Fan%1" ) ).arg( i ) ) ); + mDict.insert( "temp" + QString::number( i ), + new QString( QString( i18n( "Temperature%1" ) ).arg( i ) ) ); + } + + mDict.insert( "int00", new QString( i18n( "Total" ) ) ); + + QString num; + for ( int i = 1; i < 25; i++ ) { + num.sprintf( "%.2d", i ); + mDict.insert( "int" + num, + new QString( QString( i18n( "Int%1" ) ).arg( i - 1, 3 ) ) ); + } + + mDescriptions.setAutoDelete( true ); + // TODO: translated descriptions not yet implemented. + + mUnits.setAutoDelete( true ); + mUnits.insert( "1/s", new QString( i18n( "the unit 1 per second", "1/s" ) ) ); + mUnits.insert( "kBytes", new QString( i18n( "kBytes" ) ) ); + mUnits.insert( "min", new QString( i18n( "the unit minutes", "min" ) ) ); + mUnits.insert( "MHz", new QString( i18n( "the frequency unit", "MHz" ) ) ); + + mTypes.setAutoDelete( true ); + mTypes.insert( "integer", new QString( i18n( "Integer Value" ) ) ); + mTypes.insert( "float", new QString( i18n( "Floating Point Value" ) ) ); + mTypes.insert( "table", new QString( i18n( "Process Controller" ) ) ); + mTypes.insert( "listview", new QString( i18n( "Table" ) ) ); + + mBroadcaster = 0; + + mHostConnector = new HostConnector( 0 ); +} + +SensorManager::~SensorManager() +{ + delete mHostConnector; +} + +bool SensorManager::engageHost( const QString &hostName ) +{ + bool retVal = true; + + if ( hostName.isEmpty() || mAgents.find( hostName ) == 0 ) { + if(hostName == "localhost") { + //There was a bug where the xml file would end up not specifying to connect to localhost. + //This work around makes sure we always connect to localhost + return engage( "localhost", "", "ksysguardd", -1); + } + mHostConnector->setCurrentHostName( hostName ); + + if ( mHostConnector->exec() ) { + QString shell = ""; + QString command = ""; + int port = -1; + + /* Check which radio button is selected and set parameters + * appropriately. */ + if ( mHostConnector->useSsh() ) + shell = "ssh"; + else if ( mHostConnector->useRsh() ) + shell = "rsh"; + else if ( mHostConnector->useDaemon() ) + port = mHostConnector->port(); + else + command = mHostConnector->currentCommand(); + + if ( hostName.isEmpty() ) + retVal = engage( mHostConnector->currentHostName(), shell, + command, port ); + else + retVal = engage( hostName, shell, command, port ); + } + } + + return retVal; +} + +bool SensorManager::engage( const QString &hostName, const QString &shell, + const QString &command, int port ) +{ + SensorAgent *agent; + + if ( ( agent = mAgents.find( hostName ) ) == 0 ) { + if ( port == -1 ) + agent = new SensorShellAgent( this ); + else + agent = new SensorSocketAgent( this ); + + if ( !agent->start( hostName.ascii(), shell, command, port ) ) { + delete agent; + return false; + } + + mAgents.insert( hostName, agent ); + connect( agent, SIGNAL( reconfigure( const SensorAgent* ) ), + SLOT( reconfigure( const SensorAgent* ) ) ); + + emit update(); + return true; + } + + return false; +} + +void SensorManager::requestDisengage( const SensorAgent *agent ) +{ + /* When a sensor agent becomes disfunctional it calls this function + * to request that it is being removed from the SensorManager. It must + * not call disengage() directly since it would trigger ~SensorAgent() + * while we are still in a SensorAgent member function. + * So we have to post an event which is later caught by + * SensorManger::customEvent(). */ + QCustomEvent* event = new QCustomEvent( QEvent::User, (void*)agent ); + kapp->postEvent( this, event ); +} + +bool SensorManager::disengage( const SensorAgent *agent ) +{ + QDictIterator<SensorAgent> it( mAgents ); + + for ( ; it.current(); ++it ) + if ( it.current() == agent ) { + mAgents.remove( it.currentKey() ); + emit update(); + return true; + } + + return false; +} + +bool SensorManager::disengage( const QString &hostName ) +{ + SensorAgent *agent; + if ( ( agent = mAgents.find( hostName ) ) != 0 ) { + mAgents.remove( hostName ); + emit update(); + return true; + } + + return false; +} + +bool SensorManager::resynchronize( const QString &hostName ) +{ + SensorAgent *agent; + + if ( ( agent = mAgents.find( hostName ) ) == 0 ) + return false; + + QString shell, command; + int port; + hostInfo( hostName, shell, command, port ); + + disengage( hostName ); + + kdDebug (1215) << "Re-synchronizing connection to " << hostName << endl; + + return engage( hostName, shell, command ); +} + +void SensorManager::hostLost( const SensorAgent *agent ) +{ + emit hostConnectionLost( agent->hostName() ); + + if ( mBroadcaster ) { + QCustomEvent *event = new QCustomEvent( QEvent::User ); + event->setData( new QString( i18n( "Connection to %1 has been lost." ) + .arg( agent->hostName() ) ) ); + kapp->postEvent( mBroadcaster, event ); + } +} + +void SensorManager::notify( const QString &msg ) const +{ + /* This function relays text messages to the toplevel widget that + * displays the message in a pop-up box. It must be used for objects + * that might have been deleted before the pop-up box is closed. */ + if ( mBroadcaster ) { + QCustomEvent *event = new QCustomEvent( QEvent::User ); + event->setData( new QString( msg ) ); + kapp->postEvent( mBroadcaster, event ); + } +} + +void SensorManager::setBroadcaster( QWidget *wdg ) +{ + mBroadcaster = wdg; +} + +void SensorManager::reconfigure( const SensorAgent* ) +{ + emit update(); +} + +bool SensorManager::event( QEvent *event ) +{ + if ( event->type() == QEvent::User ) { + disengage( (const SensorAgent*)((QCustomEvent*)event)->data() ); + return true; + } + + return false; +} + +bool SensorManager::sendRequest( const QString &hostName, const QString &req, + SensorClient *client, int id ) +{ + SensorAgent *agent = mAgents.find( hostName ); + if( !agent && hostName == "localhost") { + //we should always be able to reconnect to localhost + engage("localhost", "", "ksysguardd", -1); + agent = mAgents.find( hostName ); + } + if ( agent ) { + agent->sendRequest( req, client, id ); + return true; + } + + return false; +} + +const QString SensorManager::hostName( const SensorAgent *agent) const +{ + QDictIterator<SensorAgent> it( mAgents ); + + while ( it.current() ) { + if ( it.current() == agent ) + return it.currentKey(); + ++it; + } + + return QString::null; +} + +bool SensorManager::hostInfo( const QString &hostName, QString &shell, + QString &command, int &port ) +{ + SensorAgent *agent; + if ( ( agent = mAgents.find( hostName ) ) != 0 ) { + agent->hostInfo( shell, command, port ); + return true; + } + + return false; +} + +const QString &SensorManager::translateUnit( const QString &unit ) const +{ + if ( !unit.isEmpty() && mUnits[ unit ] ) + return *mUnits[ unit ]; + else + return unit; +} + +const QString &SensorManager::translateSensorPath( const QString &path ) const +{ + if ( !path.isEmpty() && mDict[ path ] ) + return *mDict[ path ]; + else + return path; +} + +const QString &SensorManager::translateSensorType( const QString &type ) const +{ + if ( !type.isEmpty() && mTypes[ type ] ) + return *mTypes[ type ]; + else + return type; +} + +QString SensorManager::translateSensor( const QString &sensor ) const +{ + QString token, out; + int start = 0, end = 0; + for ( ; ; ) { + end = sensor.find( '/', start ); + if ( end > 0 ) + out += translateSensorPath( sensor.mid( start, end - start ) ) + "/"; + else { + out += translateSensorPath( sensor.right( sensor.length() - start ) ); + break; + } + start = end + 1; + } + + return out; +} + +void SensorManager::readProperties( KConfig *cfg ) +{ + mHostConnector->setHostNames( cfg->readListEntry( "HostList" ) ); + mHostConnector->setCommands( cfg->readListEntry( "CommandList" ) ); +} + +void +SensorManager::saveProperties( KConfig *cfg ) +{ + cfg->writeEntry( "HostList", mHostConnector->hostNames() ); + cfg->writeEntry( "CommandList", mHostConnector->commands() ); +} + +void SensorManager::disconnectClient( SensorClient *client ) +{ + QDictIterator<SensorAgent> it( mAgents ); + + for ( ; it.current(); ++it) + it.current()->disconnectClient( client ); +} + +#include "SensorManager.moc" diff --git a/ksysguard/gui/ksgrd/SensorManager.h b/ksysguard/gui/ksgrd/SensorManager.h new file mode 100644 index 000000000..8eb778009 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorManager.h @@ -0,0 +1,126 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_SENSORMANAGER_H +#define KSG_SENSORMANAGER_H + +#include <kconfig.h> + +#include <qdict.h> +#include <qobject.h> + +#include <SensorAgent.h> + +class HostConnector; + +namespace KSGRD { + +class SensorManagerIterator; + +/** + The SensorManager handles all interaction with the connected + hosts. Connections to a specific hosts are handled by + SensorAgents. Use engage() to establish a connection and + disengage() to terminate the connection. If you don't know if a + certain host is already connected use engageHost(). If there is no + connection yet or the hostname is empty, a dialog will be shown to + enter the connections details. + */ +class KDE_EXPORT SensorManager : public QObject +{ + Q_OBJECT + + friend class SensorManagerIterator; + + public: + SensorManager(); + ~SensorManager(); + + bool engageHost( const QString &hostName ); + bool engage( const QString &hostName, const QString &shell = "ssh", + const QString &command = "", int port = -1 ); + + void requestDisengage( const SensorAgent *agent ); + bool disengage( const SensorAgent *agent ); + bool disengage( const QString &hostName ); + bool resynchronize( const QString &hostName ); + void hostLost( const SensorAgent *agent ); + void notify( const QString &msg ) const; + + void setBroadcaster( QWidget *wdg ); + + virtual bool event( QEvent *event ); + + bool sendRequest( const QString &hostName, const QString &request, + SensorClient *client, int id = 0 ); + + const QString hostName( const SensorAgent *sensor ) const; + bool hostInfo( const QString &host, QString &shell, + QString &command, int &port ); + + const QString& translateUnit( const QString &unit ) const; + const QString& translateSensorPath( const QString &path ) const; + const QString& translateSensorType( const QString &type ) const; + QString translateSensor(const QString& u) const; + + void readProperties( KConfig *cfg ); + void saveProperties( KConfig *cfg ); + + void disconnectClient( SensorClient *client ); + + public slots: + void reconfigure( const SensorAgent *agent ); + + signals: + void update(); + void hostConnectionLost( const QString &hostName ); + + protected: + QDict<SensorAgent> mAgents; + + private: + /** + These dictionary stores the localized versions of the sensor + descriptions and units. + */ + QDict<QString> mDescriptions; + QDict<QString> mUnits; + QDict<QString> mDict; + QDict<QString> mTypes; + + QWidget* mBroadcaster; + + HostConnector* mHostConnector; +}; + +KDE_EXPORT extern SensorManager* SensorMgr; + +class KDE_EXPORT SensorManagerIterator : public QDictIterator<SensorAgent> +{ + public: + SensorManagerIterator( const SensorManager *sm ) + : QDictIterator<SensorAgent>( sm->mAgents ) { } + + ~SensorManagerIterator() { } +}; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/SensorShellAgent.cc b/ksysguard/gui/ksgrd/SensorShellAgent.cc new file mode 100644 index 000000000..0f06e88fe --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorShellAgent.cc @@ -0,0 +1,141 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdlib.h> + +#include <kdebug.h> +#include <kpassdlg.h> +#include <kprocess.h> + +#include "SensorClient.h" +#include "SensorManager.h" + +#include "SensorShellAgent.h" + +using namespace KSGRD; + +SensorShellAgent::SensorShellAgent( SensorManager *sm ) + : SensorAgent( sm ), mDaemon( 0 ) +{ +} + +SensorShellAgent::~SensorShellAgent() +{ + if ( mDaemon ) { + mDaemon->writeStdin( "quit\n", strlen( "quit\n" ) ); + delete mDaemon; + mDaemon = 0; + } +} + +bool SensorShellAgent::start( const QString &host, const QString &shell, + const QString &command, int ) +{ + mRetryCount = 3; + mDaemon = new KProcess; + mDaemon->setUseShell(true); + setHostName( host ); + mShell = shell; + mCommand = command; + + connect( mDaemon, SIGNAL( processExited( KProcess* ) ), + SLOT( daemonExited( KProcess* ) ) ); + connect( mDaemon, SIGNAL( receivedStdout( KProcess*, char*, int ) ), + SLOT( msgRcvd( KProcess*, char*, int ) ) ); + connect( mDaemon, SIGNAL( receivedStderr( KProcess*, char*, int ) ), + SLOT( errMsgRcvd( KProcess*, char*, int ) ) ); + connect( mDaemon, SIGNAL( wroteStdin( KProcess* ) ), + SLOT( msgSent( KProcess* ) ) ); + + QString cmd; + if ( !command.isEmpty() ) + cmd = command; + else + cmd = mShell + " " + hostName() + " ksysguardd"; + *mDaemon << cmd; + + if ( !mDaemon->start( KProcess::NotifyOnExit, KProcess::All ) ) { + sensorManager()->hostLost( this ); + kdDebug (1215) << "Command '" << cmd << "' failed" << endl; + return false; + } + + return true; +} + +void SensorShellAgent::hostInfo( QString &shell, QString &command, + int &port) const +{ + shell = mShell; + command = mCommand; + port = -1; +} + +void SensorShellAgent::msgSent( KProcess* ) +{ + setTransmitting( false ); + + // Try to send next request if available. + executeCommand(); +} + +void SensorShellAgent::msgRcvd( KProcess*, char *buffer, int buflen ) +{ + if ( !buffer || buflen == 0 ) + return; + mRetryCount = 3; //we recieved an answer, so reset our retry count back to 3 + QString aux = QString::fromLocal8Bit( buffer, buflen ); + + processAnswer( aux ); +} + +void SensorShellAgent::errMsgRcvd( KProcess*, char *buffer, int buflen ) +{ + if ( !buffer || buflen == 0 ) + return; + + QString buf = QString::fromLocal8Bit( buffer, buflen ); + + kdDebug(1215) << "SensorShellAgent: Warning, received text over stderr!" + << endl << buf << endl; +} + +void SensorShellAgent::daemonExited( KProcess *process ) +{ + kdDebug() << "daemonExited" << endl; + if ( mRetryCount-- <= 0 || !mDaemon->start( KProcess::NotifyOnExit, KProcess::All ) ) { + kdDebug() << "daemon could not be restart" << endl; + setDaemonOnLine( false ); + sensorManager()->hostLost( this ); + sensorManager()->requestDisengage( this ); + } +} + +bool SensorShellAgent::writeMsg( const char *msg, int len ) +{ + return mDaemon->writeStdin( msg, len ); +} + +bool SensorShellAgent::txReady() +{ + return !transmitting(); +} + +#include "SensorShellAgent.moc" diff --git a/ksysguard/gui/ksgrd/SensorShellAgent.h b/ksysguard/gui/ksgrd/SensorShellAgent.h new file mode 100644 index 000000000..e13413d55 --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorShellAgent.h @@ -0,0 +1,77 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_SENSORSHELLAGENT_H +#define KSG_SENSORSHELLAGENT_H + +#include <qobject.h> +#include <qptrlist.h> +#include <qguardedptr.h> + +#include <SensorAgent.h> + +class QString; + +class KProcess; + +namespace KSGRD { + +class SensorClient; +class SensorManager; + +/** + The SensorShellAgent starts a ksysguardd process and handles the + asynchronous communication. It keeps a list of pending requests + that have not been answered yet by ksysguard. The current + implementation only allowes one pending requests. Incoming requests + are queued in an input FIFO. + */ +class SensorShellAgent : public SensorAgent +{ + Q_OBJECT + + public: + SensorShellAgent( SensorManager *sm ); + ~SensorShellAgent(); + + bool start( const QString &host, const QString &shell, + const QString &command = "", int port = -1 ); + + void hostInfo( QString &shell, QString &command, int &port) const; + + private slots: + void msgSent( KProcess* ); + void msgRcvd( KProcess*, char *buffer, int buflen ); + void errMsgRcvd( KProcess*, char *buffer, int buflen ); + void daemonExited( KProcess* ); + + private: + bool writeMsg( const char *msg, int len ); + bool txReady(); + + QGuardedPtr<KProcess> mDaemon; + QString mShell; + QString mCommand; + int mRetryCount; +}; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/SensorSocketAgent.cc b/ksysguard/gui/ksgrd/SensorSocketAgent.cc new file mode 100644 index 000000000..dcb5b7f3b --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorSocketAgent.cc @@ -0,0 +1,137 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdlib.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kpassdlg.h> + +#include "SensorClient.h" +#include "SensorManager.h" + +#include "SensorSocketAgent.h" + +using namespace KSGRD; + +SensorSocketAgent::SensorSocketAgent( SensorManager *sm ) + : SensorAgent( sm ) +{ + connect( &mSocket, SIGNAL( gotError( int ) ), SLOT( error( int ) ) ); + connect( &mSocket, SIGNAL( bytesWritten( int ) ), SLOT( msgSent( int ) ) ); + connect( &mSocket, SIGNAL( readyRead() ), SLOT( msgRcvd() ) ); + connect( &mSocket, SIGNAL( closed() ), SLOT( connectionClosed() ) ); +} + +SensorSocketAgent::~SensorSocketAgent() +{ + mSocket.writeBlock( "quit\n", strlen( "quit\n" ) ); + mSocket.flush(); +} + +bool SensorSocketAgent::start( const QString &host, const QString&, + const QString&, int port ) +{ + if ( port <= 0 ) + kdDebug(1215) << "SensorSocketAgent::start: Illegal port " << port << endl; + + setHostName( host ); + mPort = port; + + mSocket.connect( hostName(), QString::number(mPort) ); + + return true; +} + +void SensorSocketAgent::hostInfo( QString &shell, QString &command, int &port ) const +{ + shell = QString::null; + command = QString::null; + port = mPort; +} + +void SensorSocketAgent::msgSent( int ) +{ + if ( mSocket.bytesToWrite() != 0 ) + return; + + setTransmitting( false ); + + // Try to send next request if available. + executeCommand(); +} + +void SensorSocketAgent::msgRcvd() +{ + int buflen = mSocket.bytesAvailable(); + char* buffer = new char[ buflen ]; + + mSocket.readBlock( buffer, buflen ); + QString buf = QString::fromLocal8Bit( buffer, buflen ); + delete [] buffer; + + processAnswer( buf ); +} + +void SensorSocketAgent::connectionClosed() +{ + setDaemonOnLine( false ); + sensorManager()->hostLost( this ); + sensorManager()->requestDisengage( this ); +} + +void SensorSocketAgent::error( int id ) +{ + switch ( id ) { + case KNetwork::KSocketBase::ConnectionRefused: + SensorMgr->notify( i18n( "Connection to %1 refused" ) + .arg( hostName() ) ); + break; + case KNetwork::KSocketBase::LookupFailure: + SensorMgr->notify( i18n( "Host %1 not found" ) + .arg( hostName() ) ); + break; + case KNetwork::KSocketBase::Timeout: + SensorMgr->notify( i18n( "Timeout at host %1") + .arg( hostName() ) ); + break; + case KNetwork::KSocketBase::NetFailure: + SensorMgr->notify( i18n( "Network failure host %1") + .arg( hostName() ) ); + break; + default: + kdDebug(1215) << "SensorSocketAgent::error() unknown error " << id << endl; + } + + setDaemonOnLine( false ); + sensorManager()->requestDisengage( this ); +} + +bool SensorSocketAgent::writeMsg( const char *msg, int len ) +{ + return ( mSocket.writeBlock( msg, len ) == len ); +} + +bool SensorSocketAgent::txReady() +{ + return !transmitting(); +} + +#include "SensorSocketAgent.moc" diff --git a/ksysguard/gui/ksgrd/SensorSocketAgent.h b/ksysguard/gui/ksgrd/SensorSocketAgent.h new file mode 100644 index 000000000..b422d3a9b --- /dev/null +++ b/ksysguard/gui/ksgrd/SensorSocketAgent.h @@ -0,0 +1,71 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_SENSORSOCKETAGENT_H +#define KSG_SENSORSOCKETAGENT_H + +#include <qptrlist.h> +#include <kbufferedsocket.h> + +#include <SensorAgent.h> + +class QString; + +namespace KSGRD { + +class SensorClient; + +/** + The SensorSocketAgent connects to a ksysguardd via a TCP + connection. It keeps a list of pending requests that have not been + answered yet by ksysguard. The current implementation only allowes + one pending requests. Incoming requests are queued in an input + FIFO. + */ +class SensorSocketAgent : public SensorAgent +{ + Q_OBJECT + + public: + SensorSocketAgent( SensorManager *sm ); + ~SensorSocketAgent(); + + bool start( const QString &host, const QString &shell, + const QString &command = "", int port = -1 ); + + void hostInfo( QString &shell, QString &command, int &port ) const; + + private slots: + void connectionClosed(); + void msgSent( int ); + void msgRcvd(); + void error( int ); + + private: + bool writeMsg( const char *msg, int len ); + bool txReady(); + + KNetwork::KBufferedSocket mSocket; + int mPort; +}; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/StyleEngine.cc b/ksysguard/gui/ksgrd/StyleEngine.cc new file mode 100644 index 000000000..ccea0a7c2 --- /dev/null +++ b/ksysguard/gui/ksgrd/StyleEngine.cc @@ -0,0 +1,176 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <qimage.h> +#include <qpushbutton.h> +#include <qspinbox.h> + +#include <kconfig.h> +#include <klocale.h> + +#include "StyleSettings.h" + +#include "StyleEngine.h" + +using namespace KSGRD; + +StyleEngine* KSGRD::Style; + +StyleEngine::StyleEngine() +{ + mFirstForegroundColor = QColor( 0x6894c9 ); // light blue + mSecondForegroundColor = QColor( 0x6894c9 ); // light blue + mAlarmColor = QColor( 255, 0, 0 ); + mBackgroundColor = QColor( 0x313031 ); // almost black + mFontSize = 9; + + mSensorColors.append( QColor( 0x1889ff ) ); // soft blue + mSensorColors.append( QColor( 0xff7f08 ) ); // reddish + mSensorColors.append( QColor( 0xffeb14 ) ); // bright yellow + + uint v = 0x00ff00; + for ( uint i = mSensorColors.count(); i < 32; ++i ) { + v = ( ( ( v + 82 ) & 0xff ) << 23 ) | ( v >> 8 ); + mSensorColors.append( QColor( v & 0xff, ( v >> 16 ) & 0xff, ( v >> 8 ) & 0xff ) ); + } +} + +StyleEngine::~StyleEngine() +{ +} + +void StyleEngine::readProperties( KConfig *cfg ) +{ + mFirstForegroundColor = cfg->readColorEntry( "fgColor1", &mFirstForegroundColor ); + mSecondForegroundColor = cfg->readColorEntry( "fgColor2", &mSecondForegroundColor ); + mAlarmColor = cfg->readColorEntry( "alarmColor", &mAlarmColor ); + mBackgroundColor = cfg->readColorEntry( "backgroundColor", &mBackgroundColor ); + mFontSize = cfg->readNumEntry( "fontSize", mFontSize ); + + QStringList list = cfg->readListEntry( "sensorColors" ); + if ( !list.isEmpty() ) { + mSensorColors.clear(); + QStringList::Iterator it; + for ( it = list.begin(); it != list.end(); ++it ) + mSensorColors.append( QColor( *it ) ); + } +} + +void StyleEngine::saveProperties( KConfig *cfg ) +{ + cfg->writeEntry( "fgColor1", mFirstForegroundColor ); + cfg->writeEntry( "fgColor2", mSecondForegroundColor ); + cfg->writeEntry( "alarmColor", mAlarmColor ); + cfg->writeEntry( "backgroundColor", mBackgroundColor ); + cfg->writeEntry( "fontSize", mFontSize ); + + QStringList list; + QValueList<QColor>::Iterator it; + for ( it = mSensorColors.begin(); it != mSensorColors.end(); ++it ) + list.append( (*it).name() ); + + cfg->writeEntry( "sensorColors", list ); +} + +const QColor &StyleEngine::firstForegroundColor() const +{ + return mFirstForegroundColor; +} + +const QColor &StyleEngine::secondForegroundColor() const +{ + return mSecondForegroundColor; +} + +const QColor &StyleEngine::alarmColor() const +{ + return mAlarmColor; +} + +const QColor &StyleEngine::backgroundColor() const +{ + return mBackgroundColor; +} + +uint StyleEngine::fontSize() const +{ + return mFontSize; +} + +const QColor& StyleEngine::sensorColor( uint pos ) +{ + static QColor dummy; + + if ( pos < mSensorColors.count() ) + return *mSensorColors.at( pos ); + else + return dummy; +} + +uint StyleEngine::numSensorColors() const +{ + return mSensorColors.count(); +} + +void StyleEngine::configure() +{ + mSettingsDialog = new StyleSettings( 0 ); + + mSettingsDialog->setFirstForegroundColor( mFirstForegroundColor ); + mSettingsDialog->setSecondForegroundColor( mSecondForegroundColor ); + mSettingsDialog->setAlarmColor( mAlarmColor ); + mSettingsDialog->setBackgroundColor( mBackgroundColor ); + mSettingsDialog->setFontSize( mFontSize ); + mSettingsDialog->setSensorColors( mSensorColors ); + + connect( mSettingsDialog, SIGNAL( applyClicked() ), + this, SLOT( applyToWorksheet() ) ); + + if ( mSettingsDialog->exec() ) + apply(); + + delete mSettingsDialog; + mSettingsDialog = 0; +} + +void StyleEngine::applyToWorksheet() +{ + apply(); + emit applyStyleToWorksheet(); +} + +void StyleEngine::apply() +{ + if ( !mSettingsDialog ) + return; + + mFirstForegroundColor = mSettingsDialog->firstForegroundColor(); + mSecondForegroundColor = mSettingsDialog->secondForegroundColor(); + mAlarmColor = mSettingsDialog->alarmColor(); + mBackgroundColor = mSettingsDialog->backgroundColor(); + mFontSize = mSettingsDialog->fontSize(); + + mSensorColors = mSettingsDialog->sensorColors(); +} + +#include "StyleEngine.moc" diff --git a/ksysguard/gui/ksgrd/StyleEngine.h b/ksysguard/gui/ksgrd/StyleEngine.h new file mode 100644 index 000000000..d896a2422 --- /dev/null +++ b/ksysguard/gui/ksgrd/StyleEngine.h @@ -0,0 +1,86 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_STYLEENGINE_H +#define KSG_STYLEENGINE_H + +#include <qcolor.h> +#include <qobject.h> +#include <qptrlist.h> + +#include <kdemacros.h> + +class KConfig; + +class QListBoxItem; + +class StyleSettings; + +namespace KSGRD { + +class KDE_EXPORT StyleEngine : public QObject +{ + Q_OBJECT + + public: + StyleEngine(); + ~StyleEngine(); + + void readProperties( KConfig* ); + void saveProperties( KConfig* ); + + const QColor& firstForegroundColor() const; + const QColor& secondForegroundColor() const; + const QColor& alarmColor() const; + const QColor& backgroundColor() const; + + uint fontSize() const; + + const QColor& sensorColor( uint pos ); + uint numSensorColors() const; + + public slots: + void configure(); + void applyToWorksheet(); + + signals: + void applyStyleToWorksheet(); + + private: + void apply(); + + QColor mFirstForegroundColor; + QColor mSecondForegroundColor; + QColor mAlarmColor; + QColor mBackgroundColor; + uint mFontSize; + QValueList<QColor> mSensorColors; + + StyleSettings *mSettingsDialog; +}; + +KDE_EXPORT extern StyleEngine* Style; + +} + +#endif diff --git a/ksysguard/gui/ksgrd/StyleSettings.cc b/ksysguard/gui/ksgrd/StyleSettings.cc new file mode 100644 index 000000000..19a924cbe --- /dev/null +++ b/ksysguard/gui/ksgrd/StyleSettings.cc @@ -0,0 +1,201 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <qimage.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlistbox.h> +#include <qpixmap.h> +#include <qpushbutton.h> +#include <qspinbox.h> +#include <qtabwidget.h> + +#include <kaccelmanager.h> +#include <kcolorbutton.h> +#include <kcolordialog.h> +#include <klocale.h> + +#include "StyleSettings.h" + +StyleSettings::StyleSettings( QWidget *parent, const char *name ) + : KDialogBase( Tabbed, i18n( "Global Style Settings" ), Help | Ok | Apply | + Cancel, Ok, parent, name, true, true ) +{ + QFrame *page = addPage( i18n( "Display Style" ) ); + QGridLayout *layout = new QGridLayout( page, 6, 2, 0, spacingHint() ); + + QLabel *label = new QLabel( i18n( "First foreground color:" ), page ); + layout->addWidget( label, 0, 0 ); + + mFirstForegroundColor = new KColorButton( page ); + layout->addWidget( mFirstForegroundColor, 0, 1 ); + label->setBuddy( mFirstForegroundColor ); + + label = new QLabel( i18n( "Second foreground color:" ), page ); + layout->addWidget( label, 1, 0 ); + + mSecondForegroundColor = new KColorButton( page ); + layout->addWidget( mSecondForegroundColor, 1, 1 ); + label->setBuddy( mSecondForegroundColor ); + + label = new QLabel( i18n( "Alarm color:" ), page ); + layout->addWidget( label, 2, 0 ); + + mAlarmColor = new KColorButton( page ); + layout->addWidget( mAlarmColor, 2, 1 ); + label->setBuddy( mAlarmColor ); + + label = new QLabel( i18n( "Background color:" ), page ); + layout->addWidget( label, 3, 0 ); + + mBackgroundColor = new KColorButton( page ); + layout->addWidget( mBackgroundColor, 3, 1 ); + label->setBuddy( mBackgroundColor ); + + label = new QLabel( i18n( "Font size:" ), page ); + layout->addWidget( label, 4, 0 ); + + mFontSize = new QSpinBox( 7, 48, 1, page ); + mFontSize->setValue( 8 ); + layout->addWidget( mFontSize, 4, 1 ); + label->setBuddy( mFontSize ); + + layout->setRowStretch( 5, 1 ); + + page = addPage( i18n( "Sensor Colors" ) ); + layout = new QGridLayout( page, 1, 2, 0, spacingHint() ); + + mColorListBox = new QListBox( page ); + layout->addWidget( mColorListBox, 0, 0 ); + + mEditColorButton = new QPushButton( i18n( "Change Color..." ), page ); + mEditColorButton->setEnabled( false ); + layout->addWidget( mEditColorButton, 0, 1, Qt::AlignTop ); + + connect( mColorListBox, SIGNAL( selectionChanged( QListBoxItem* ) ), + SLOT( selectionChanged( QListBoxItem* ) ) ); + connect( mColorListBox, SIGNAL( doubleClicked( QListBoxItem* ) ), + SLOT( editSensorColor() ) ); + connect( mEditColorButton, SIGNAL( clicked() ), + SLOT( editSensorColor() ) ); + + KAcceleratorManager::manage( this ); +} + +StyleSettings::~StyleSettings() +{ +} + +void StyleSettings::setFirstForegroundColor( const QColor &color ) +{ + mFirstForegroundColor->setColor( color ); +} + +QColor StyleSettings::firstForegroundColor() const +{ + return mFirstForegroundColor->color(); +} + +void StyleSettings::setSecondForegroundColor( const QColor &color ) +{ + mSecondForegroundColor->setColor( color ); +} + +QColor StyleSettings::secondForegroundColor() const +{ + return mSecondForegroundColor->color(); +} + +void StyleSettings::setAlarmColor( const QColor &color ) +{ + mAlarmColor->setColor( color ); +} + +QColor StyleSettings::alarmColor() const +{ + return mAlarmColor->color(); +} + +void StyleSettings::setBackgroundColor( const QColor &color ) +{ + mBackgroundColor->setColor( color ); +} + +QColor StyleSettings::backgroundColor() const +{ + return mBackgroundColor->color(); +} + +void StyleSettings::setFontSize( uint size ) +{ + mFontSize->setValue( size ); +} + +uint StyleSettings::fontSize() const +{ + return mFontSize->value(); +} + +void StyleSettings::setSensorColors( const QValueList<QColor> &list ) +{ + mColorListBox->clear(); + + for ( uint i = 0; i < list.count(); ++i ) { + QPixmap pm( 12, 12 ); + pm.fill( *list.at( i ) ); + mColorListBox->insertItem( pm, i18n( "Color %1" ).arg( i ) ); + } +} + +QValueList<QColor> StyleSettings::sensorColors() +{ + QValueList<QColor> list; + + for ( uint i = 0; i < mColorListBox->count(); ++i ) + list.append( QColor( mColorListBox->pixmap( i )->convertToImage().pixel( 1, 1 ) ) ); + + return list; +} + +void StyleSettings::editSensorColor() +{ + int pos = mColorListBox->currentItem(); + + if ( pos < 0 ) + return; + + QColor color = mColorListBox->pixmap( pos )->convertToImage().pixel( 1, 1 ); + + if ( KColorDialog::getColor( color ) == KColorDialog::Accepted ) { + QPixmap pm( 12, 12 ); + pm.fill( color ); + mColorListBox->changeItem( pm, mColorListBox->text( pos ), pos ); + } +} + +void StyleSettings::selectionChanged( QListBoxItem *item ) +{ + mEditColorButton->setEnabled( item != 0 ); +} + +#include "StyleSettings.moc" diff --git a/ksysguard/gui/ksgrd/StyleSettings.h b/ksysguard/gui/ksgrd/StyleSettings.h new file mode 100644 index 000000000..d16b5e723 --- /dev/null +++ b/ksysguard/gui/ksgrd/StyleSettings.h @@ -0,0 +1,78 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_STYLESETTINGS_H +#define KSG_STYLESETTINGS_H + +#include <kdialogbase.h> + +#include <qcolor.h> + +class KColorButton; + +class QListBoxItem; +class QPushButton; + +class StyleSettings : public KDialogBase +{ + Q_OBJECT + + public: + StyleSettings( QWidget *parent = 0, const char *name = 0 ); + ~StyleSettings(); + + void setFirstForegroundColor( const QColor &color ); + QColor firstForegroundColor() const; + + void setSecondForegroundColor( const QColor &color ); + QColor secondForegroundColor() const; + + void setAlarmColor( const QColor &color ); + QColor alarmColor() const; + + void setBackgroundColor( const QColor &color ); + QColor backgroundColor() const; + + void setFontSize( uint size ); + uint fontSize() const; + + void setSensorColors( const QValueList<QColor> &list ); + QValueList<QColor> sensorColors(); + + private slots: + void editSensorColor(); + void selectionChanged( QListBoxItem* ); + + private: + KColorButton *mFirstForegroundColor; + KColorButton *mSecondForegroundColor; + KColorButton *mAlarmColor; + KColorButton *mBackgroundColor; + + QSpinBox *mFontSize; + + QListBox *mColorListBox; + QPushButton *mEditColorButton; +}; + +#endif diff --git a/ksysguard/gui/ksgrd/TimerSettings.cc b/ksysguard/gui/ksgrd/TimerSettings.cc new file mode 100644 index 000000000..4806f7d8a --- /dev/null +++ b/ksysguard/gui/ksgrd/TimerSettings.cc @@ -0,0 +1,94 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#include <kaccelmanager.h> +#include <klocale.h> + +#include <qcheckbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qspinbox.h> +#include <qwhatsthis.h> + +#include "TimerSettings.h" + +TimerSettings::TimerSettings( QWidget *parent, const char *name ) + : KDialogBase( Plain, i18n( "Timer Settings" ), Ok | Cancel, + Ok, parent, name, true, true ) +{ + QFrame *page = plainPage(); + + QGridLayout *layout = new QGridLayout( page, 2, 2, 0, spacingHint() ); + + mUseGlobalUpdate = new QCheckBox( i18n( "Use update interval of worksheet" ), page ); + layout->addMultiCellWidget( mUseGlobalUpdate, 0, 0, 0, 1 ); + + mLabel = new QLabel( i18n( "Update interval:" ), page ); + layout->addWidget( mLabel, 1, 0 ); + + mInterval = new QSpinBox( 1, 300, 1, page ); + mInterval->setValue( 2 ); + mInterval->setSuffix( i18n( " sec" ) ); + layout->addWidget( mInterval, 1, 1 ); + mLabel->setBuddy( mInterval ); + QWhatsThis::add( mInterval, i18n( "All displays of the sheet are updated at the rate specified here." ) ); + + connect( mUseGlobalUpdate, SIGNAL( toggled( bool ) ), + SLOT( globalUpdateChanged( bool ) ) ); + + mUseGlobalUpdate->setChecked( true ); + + KAcceleratorManager::manage( this ); +} + +TimerSettings::~TimerSettings() +{ +} + +void TimerSettings::setUseGlobalUpdate( bool value ) +{ + mUseGlobalUpdate->setChecked( value ); +} + +bool TimerSettings::useGlobalUpdate() const +{ + return mUseGlobalUpdate->isChecked(); +} + +void TimerSettings::setInterval( int interval ) +{ + mInterval->setValue( interval ); +} + +int TimerSettings::interval() const +{ + return mInterval->value(); +} + +void TimerSettings::globalUpdateChanged( bool value ) +{ + mInterval->setEnabled( !value ); + mLabel->setEnabled( !value ); +} + +#include "TimerSettings.moc" diff --git a/ksysguard/gui/ksgrd/TimerSettings.h b/ksysguard/gui/ksgrd/TimerSettings.h new file mode 100644 index 000000000..daf2eda6f --- /dev/null +++ b/ksysguard/gui/ksgrd/TimerSettings.h @@ -0,0 +1,56 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. + Please do not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_TIMERSETTINGS_H +#define KSG_TIMERSETTINGS_H + +#include <kdialogbase.h> + +class QCheckBox; +class QLabel; +class QSpinBox; + +class KDE_EXPORT TimerSettings : public KDialogBase +{ + Q_OBJECT + + public: + TimerSettings( QWidget *parent, const char *name = 0 ); + ~TimerSettings(); + + void setUseGlobalUpdate( bool value ); + bool useGlobalUpdate() const; + + void setInterval( int interval ); + int interval() const; + + private slots: + void globalUpdateChanged( bool ); + + private: + QCheckBox* mUseGlobalUpdate; + QLabel* mLabel; + QSpinBox* mInterval; +}; + +#endif diff --git a/ksysguard/gui/ksysguard.cc b/ksysguard/gui/ksysguard.cc new file mode 100644 index 000000000..4750a380f --- /dev/null +++ b/ksysguard/gui/ksysguard.cc @@ -0,0 +1,650 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger + <cs@kde.org>. Please do not commit any changes without consulting + me first. Thanks! + + KSysGuard has been written with some source code and ideas from + ktop (<1.0). Early versions of ktop have been written by Bernd + Johannes Wuebben <wuebben@math.cornell.edu> and Nicolas Leclercq + <nicknet@planete.net>. + +*/ + +#include <assert.h> +#include <ctype.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <kaboutdata.h> +#include <kaction.h> +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <kdebug.h> +#include <kedittoolbar.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <ksgrd/SensorAgent.h> +#include <ksgrd/SensorManager.h> +#include <ksgrd/StyleEngine.h> +#include <kstandarddirs.h> +#include <kstatusbar.h> +#include <kstdaction.h> +#include <kwin.h> +#include <kwinmodule.h> +#include <dnssd/remoteservice.h> + + +#include "../version.h" +#include "SensorBrowser.h" +#include "Workspace.h" + +#include "ksysguard.h" + +static const char Description[] = I18N_NOOP( "KDE system guard" ); +TopLevel* topLevel; + +/** + This is the constructor for the main widget. It sets up the menu and the + TaskMan widget. + */ +TopLevel::TopLevel( const char *name ) + : KMainWindow( 0, name ), DCOPObject( "KSysGuardIface" ) +{ + setPlainCaption( i18n( "KDE System Guard" ) ); + mDontSaveSession = false; + mTimerId = -1; + + mSplitter = new QSplitter( this ); + mSplitter->setOrientation( Horizontal ); + mSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() ); + setCentralWidget( mSplitter ); + + mSensorBrowser = new SensorBrowser( mSplitter, KSGRD::SensorMgr ); + + mServiceBrowser = new DNSSD::ServiceBrowser("_ksysguard._tcp", 0, true); + connect(mServiceBrowser,SIGNAL(serviceAdded(DNSSD::RemoteService::Ptr)),this, + SLOT(serviceAdded(DNSSD::RemoteService::Ptr))); + + mWorkSpace = new Workspace( mSplitter ); + connect( mWorkSpace, SIGNAL( announceRecentURL( const KURL& ) ), + SLOT( registerRecentURL( const KURL& ) ) ); + connect( mWorkSpace, SIGNAL( setCaption( const QString&, bool ) ), + SLOT( setCaption( const QString&, bool ) ) ); + connect( KSGRD::Style, SIGNAL( applyStyleToWorksheet() ), mWorkSpace, + SLOT( applyStyle() ) ); + + /* Create the status bar. It displays some information about the + * number of processes and the memory consumption of the local + * host. */ + statusBar()->insertFixedItem( i18n( "88888 Processes" ), 0 ); + statusBar()->insertFixedItem( i18n( "Memory: 88888888888 kB used, " + "88888888888 kB free" ), 1 ); + statusBar()->insertFixedItem( i18n( "Swap: 888888888 kB used, " + "888888888 kB free" ), 2 ); + statusBar()->hide(); + + // create actions for menue entries + new KAction( i18n( "&New Worksheet..." ), "tab_new", 0, mWorkSpace, + SLOT( newWorkSheet() ), actionCollection(), "new_worksheet" ); + + new KAction( i18n( "Import Worksheet..." ), "fileopen", 0, mWorkSpace, + SLOT( loadWorkSheet() ), actionCollection(), "import_worksheet" ); + + mActionOpenRecent = new KRecentFilesAction( i18n( "&Import Recent Worksheet" ),"fileopen", 0, + mWorkSpace, SLOT( loadWorkSheet( const KURL& ) ), actionCollection(), "recent_import_worksheet" ); + + new KAction( i18n( "&Remove Worksheet" ), "tab_remove", 0, mWorkSpace, + SLOT( deleteWorkSheet() ), actionCollection(), "remove_worksheet" ); + + new KAction( i18n( "&Export Worksheet..." ), "filesaveas", 0, mWorkSpace, + SLOT( saveWorkSheetAs() ), actionCollection(), "export_worksheet" ); + + KStdAction::quit( this, SLOT( close() ), actionCollection() ); + + new KAction( i18n( "C&onnect Host..." ), "connect_established", 0, this, + SLOT( connectHost() ), actionCollection(), "connect_host" ); + new KAction( i18n( "D&isconnect Host" ), "connect_no", 0, this, + SLOT( disconnectHost() ), actionCollection(), "disconnect_host" ); + +// KStdAction::cut( mWorkSpace, SLOT( cut() ), actionCollection() ); +// KStdAction::copy( mWorkSpace, SLOT( copy() ), actionCollection() ); +// KStdAction::paste( mWorkSpace, SLOT( paste() ), actionCollection() ); + new KAction( i18n( "&Worksheet Properties" ), "configure", 0, mWorkSpace, + SLOT( configure() ), actionCollection(), "configure_sheet" ); + + new KAction( i18n( "Load Standard Sheets" ), "revert", + 0, this, SLOT( resetWorkSheets() ), + actionCollection(), "revert_all_worksheets" ); + + new KAction( i18n( "Configure &Style..." ), "colorize", 0, this, + SLOT( editStyle() ), actionCollection(), "configure_style" ); + + // TODO remove resize and fix so sizeHints() determines default size. + if (!initialGeometrySet()) + resize( 640, 480 ); + setupGUI(ToolBar | Keys | StatusBar | Create); + setAutoSaveSettings(); +} + + +/* + * DCOP Interface functions + */ +void TopLevel::resetWorkSheets() +{ + if ( KMessageBox::warningContinueCancel( this, + i18n( "Do you really want to restore the default worksheets?" ), + i18n( "Reset All Worksheets" ), + i18n("Reset"), + "AskResetWorkSheets") == KMessageBox::Cancel ) + return; + + mWorkSpace->removeAllWorkSheets(); + + KStandardDirs* kstd = KGlobal::dirs(); + kstd->addResourceType( "data", "share/apps/ksysguard" ); + + QString workDir = kstd->saveLocation( "data", "ksysguard" ); + + QString file = kstd->findResource( "data", "SystemLoad.sgrd" ); + QString newFile = workDir + "/" + i18n( "System Load" ) + ".sgrd"; + if ( !file.isEmpty() ) + mWorkSpace->restoreWorkSheet( file, newFile ); + + file = kstd->findResource( "data", "ProcessTable.sgrd" ); + newFile = workDir + "/" + i18n( "Process Table" ) + ".sgrd"; + if ( !file.isEmpty() ) + mWorkSpace->restoreWorkSheet( file, newFile ); +} + +void TopLevel::showProcesses() +{ + mWorkSpace->showProcesses(); +} + +void TopLevel::showOnCurrentDesktop() +{ + KWin::setOnDesktop( winId(), KWin::currentDesktop() ); + kapp->updateUserTimestamp(); + KWin::forceActiveWindow( winId() ); +} + +void TopLevel::loadWorkSheet( const QString &fileName ) +{ + mWorkSpace->loadWorkSheet( KURL( fileName ) ); +} + +void TopLevel::removeWorkSheet( const QString &fileName ) +{ + mWorkSpace->deleteWorkSheet( fileName ); +} + +QStringList TopLevel::listSensors( const QString &hostName ) +{ + return mSensorBrowser->listSensors( hostName ); +} + +QStringList TopLevel::listHosts() +{ + return mSensorBrowser->listHosts(); +} + +QString TopLevel::readIntegerSensor( const QString &sensorLocator ) +{ + QString host = sensorLocator.left( sensorLocator.find( ':' ) ); + QString sensor = sensorLocator.right( sensorLocator.length() - + sensorLocator.find( ':' ) - 1 ); + + DCOPClientTransaction *dcopTransaction = kapp->dcopClient()->beginTransaction(); + mDCopFIFO.prepend( dcopTransaction ); + + KSGRD::SensorMgr->engage( host, "", "ksysguardd" ); + KSGRD::SensorMgr->sendRequest( host, sensor, (KSGRD::SensorClient*)this, 133 ); + + return QString::null; +} + +QStringList TopLevel::readListSensor( const QString& sensorLocator ) +{ + QStringList retval; + + QString host = sensorLocator.left( sensorLocator.find( ':' ) ); + QString sensor = sensorLocator.right( sensorLocator.length() - + sensorLocator.find( ':' ) - 1 ); + + DCOPClientTransaction *dcopTransaction = kapp->dcopClient()->beginTransaction(); + mDCopFIFO.prepend( dcopTransaction ); + + KSGRD::SensorMgr->engage( host, "", "ksysguardd" ); + KSGRD::SensorMgr->sendRequest( host, sensor, (KSGRD::SensorClient*)this, 134 ); + + return retval; +} +/* + * End of DCOP Interface section + */ + +void TopLevel::serviceAdded(DNSSD::RemoteService::Ptr srv) +{ + KSGRD::SensorMgr->engage( srv->hostName(), "", "", srv->port() ); +} + +void TopLevel::registerRecentURL( const KURL &url ) +{ + mActionOpenRecent->addURL( url ); +} + +void TopLevel::beATaskManager() +{ + mWorkSpace->showProcesses(); + + // Avoid displaying splitter widget + mSensorBrowser->hide(); + + // No toolbar and status bar in taskmanager mode. + toolBar( "mainToolBar" )->hide(); + + mDontSaveSession = true; + + stateChanged( "showProcessState" ); +} + +void TopLevel::showRequestedSheets() +{ + toolBar( "mainToolBar" )->hide(); + + QValueList<int> sizes; + sizes.append( 0 ); + sizes.append( 100 ); + mSplitter->setSizes( sizes ); +} + +void TopLevel::initStatusBar() +{ + KSGRD::SensorMgr->engage( "localhost", "", "ksysguardd" ); + /* Request info about the swap space size and the units it is + * measured in. The requested info will be received by + * answerReceived(). */ + KSGRD::SensorMgr->sendRequest( "localhost", "mem/swap/used?", + (KSGRD::SensorClient*)this, 5 ); + updateStatusBar(); + mServiceBrowser->startBrowse(); + + KToggleAction *sb = dynamic_cast<KToggleAction*>(action("options_show_statusbar")); + if (sb) + connect(sb, SIGNAL(toggled(bool)), this, SLOT(updateStatusBar())); +} + +void TopLevel::updateStatusBar() +{ + if ( mTimerId == -1 ) + mTimerId = startTimer( 2000 ); + + // call timerEvent to fill the status bar with real values + timerEvent( 0 ); +} + +void TopLevel::connectHost() +{ + KSGRD::SensorMgr->engageHost( "" ); +} + +void TopLevel::disconnectHost() +{ + mSensorBrowser->disconnect(); +} + +void TopLevel::editToolbars() +{ + saveMainWindowSettings( kapp->config() ); + KEditToolbar dlg( actionCollection() ); + connect( &dlg, SIGNAL( newToolbarConfig() ), this, + SLOT( slotNewToolbarConfig() ) ); + + dlg.exec(); +} + +void TopLevel::slotNewToolbarConfig() +{ + createGUI(); + applyMainWindowSettings( kapp->config() ); +} + +void TopLevel::editStyle() +{ + KSGRD::Style->configure(); +} + +void TopLevel::customEvent( QCustomEvent *e ) +{ + if ( e->type() == QEvent::User ) { + /* Due to the asynchronous communication between ksysguard and its + * back-ends, we sometimes need to show message boxes that were + * triggered by objects that have died already. */ + KMessageBox::error( this, *((QString*)e->data()) ); + delete (QString*)e->data(); + } +} + +void TopLevel::timerEvent( QTimerEvent* ) +{ + if ( statusBar()->isVisibleTo( this ) ) { + /* Request some info about the memory status. The requested + * information will be received by answerReceived(). */ + KSGRD::SensorMgr->sendRequest( "localhost", "pscount", + (KSGRD::SensorClient*)this, 0 ); + KSGRD::SensorMgr->sendRequest( "localhost", "mem/physical/free", + (KSGRD::SensorClient*)this, 1 ); + KSGRD::SensorMgr->sendRequest( "localhost", "mem/physical/used", + (KSGRD::SensorClient*)this, 2 ); + KSGRD::SensorMgr->sendRequest( "localhost", "mem/swap/free", + (KSGRD::SensorClient*)this, 3 ); + KSGRD::SensorMgr->sendRequest( "localhost", "mem/swap/used", + (KSGRD::SensorClient*)this, 4 ); + } +} + +bool TopLevel::queryClose() +{ + if ( !mDontSaveSession ) { + if ( !mWorkSpace->saveOnQuit() ) + return false; + + saveProperties( kapp->config() ); + kapp->config()->sync(); + } + + return true; +} + +void TopLevel::readProperties( KConfig *cfg ) +{ + /* we can ignore 'isMaximized' because we can't set the window + maximized, so we save the coordinates instead */ + if ( cfg->readBoolEntry( "isMinimized" ) == true ) + showMinimized(); + + QValueList<int> sizes = cfg->readIntListEntry( "SplitterSizeList" ); + if ( sizes.isEmpty() ) { + // start with a 30/70 ratio + sizes.append( 30 ); + sizes.append( 70 ); + } + mSplitter->setSizes( sizes ); + + KSGRD::SensorMgr->readProperties( cfg ); + KSGRD::Style->readProperties( cfg ); + + mWorkSpace->readProperties( cfg ); + + mActionOpenRecent->loadEntries( cfg ); + + applyMainWindowSettings( cfg ); +} + +void TopLevel::saveProperties( KConfig *cfg ) +{ + mActionOpenRecent->saveEntries( cfg ); + + cfg->writeEntry( "isMinimized", isMinimized() ); + cfg->writeEntry( "SplitterSizeList", mSplitter->sizes() ); + + KSGRD::Style->saveProperties( cfg ); + KSGRD::SensorMgr->saveProperties( cfg ); + + saveMainWindowSettings( cfg ); + mWorkSpace->saveProperties( cfg ); +} + +void TopLevel::answerReceived( int id, const QString &answer ) +{ + QString s; + static QString unit; + static long mUsed = 0; + static long mFree = 0; + static long sUsed = 0; + static long sFree = 0; + + switch ( id ) { + case 0: + // yes, I know there is never 1 process, but that's the way + // singular vs. plural works :/ + // + // To use pluralForms, though, you need to convert to + // an integer, not use the QString straight. + s = i18n( "1 Process", "%n Processes", answer.toInt() ); + statusBar()->changeItem( s, 0 ); + break; + + case 1: + mFree = answer.toLong(); + break; + + case 2: + mUsed = answer.toLong(); + s = i18n( "Memory: %1 %2 used, %3 %4 free" ) + .arg( KGlobal::locale()->formatNumber( mUsed, 0 ) ).arg( unit ) + .arg( KGlobal::locale()->formatNumber( mFree, 0 ) ).arg( unit ); + statusBar()->changeItem( s, 1 ); + break; + + case 3: + sFree = answer.toLong(); + setSwapInfo( sUsed, sFree, unit ); + break; + + case 4: + sUsed = answer.toLong(); + setSwapInfo( sUsed, sFree, unit ); + break; + + case 5: { + KSGRD::SensorIntegerInfo info( answer ); + unit = KSGRD::SensorMgr->translateUnit( info.unit() ); + } + + case 133: { + QCString replyType = "QString"; + QByteArray replyData; + QDataStream reply( replyData, IO_WriteOnly ); + reply << answer; + + DCOPClientTransaction *dcopTransaction = mDCopFIFO.last(); + kapp->dcopClient()->endTransaction( dcopTransaction, replyType, replyData ); + mDCopFIFO.removeLast(); + break; + } + + case 134: { + QStringList resultList; + QCString replyType = "QStringList"; + QByteArray replyData; + QDataStream reply( replyData, IO_WriteOnly ); + + KSGRD::SensorTokenizer lines( answer, '\n' ); + + for ( unsigned int i = 0; i < lines.count(); i++ ) + resultList.append( lines[ i ] ); + + reply << resultList; + + DCOPClientTransaction *dcopTransaction = mDCopFIFO.last(); + kapp->dcopClient()->endTransaction( dcopTransaction, replyType, replyData ); + mDCopFIFO.removeLast(); + break; + } + } +} + +void TopLevel::setSwapInfo( long used, long free, const QString &unit ) +{ + QString msg; + if ( used == 0 && free == 0 ) // no swap available + msg = i18n( "No swap space available" ); + else { + msg = i18n( "Swap: %1 %2 used, %3 %4 free" ) + .arg( KGlobal::locale()->formatNumber( used, 0 ) ).arg( unit ) + .arg( KGlobal::locale()->formatNumber( free, 0 ) ).arg( unit ); + } + + statusBar()->changeItem( msg, 2 ); +} + +static const KCmdLineOptions options[] = { + { "showprocesses", I18N_NOOP( "Show only process list of local host" ), 0 }, + { "+[worksheet]", I18N_NOOP( "Optional worksheet files to load" ), 0 }, + KCmdLineLastOption +}; + +/* + * Once upon a time... + */ +int main( int argc, char** argv ) +{ + // initpipe is used to keep the parent process around till the child + // has registered with dcop. + int initpipe[ 2 ]; + pipe( initpipe ); + + /* This forking will put ksysguard in it's on session not having a + * controlling terminal attached to it. This prevents ssh from + * using this terminal for password requests. Unfortunately you + * now need a ssh with ssh-askpass support to popup an X dialog to + * enter the password. Currently only the original ssh provides this + * but not open-ssh. */ + + pid_t pid; + if ( ( pid = fork() ) < 0 ) + return -1; + else + if ( pid != 0 ) { + close( initpipe[ 1 ] ); + + // wait till init is complete + char c; + while( read( initpipe[ 0 ], &c, 1 ) < 0 ); + + // then exit + close( initpipe[ 0 ] ); + exit( 0 ); + } + + close( initpipe[ 0 ] ); + setsid(); + + KAboutData aboutData( "ksysguard", I18N_NOOP( "KDE System Guard" ), + KSYSGUARD_VERSION, Description, KAboutData::License_GPL, + I18N_NOOP( "(c) 1996-2002 The KSysGuard Developers" ) ); + aboutData.addAuthor( "Chris Schlaeger", "Current Maintainer", "cs@kde.org" ); + aboutData.addAuthor( "Tobias Koenig", 0, "tokoe@kde.org" ); + aboutData.addAuthor( "Nicolas Leclercq", 0, "nicknet@planete.net" ); + aboutData.addAuthor( "Alex Sanda", 0, "alex@darkstart.ping.at" ); + aboutData.addAuthor( "Bernd Johannes Wuebben", 0, "wuebben@math.cornell.edu" ); + aboutData.addAuthor( "Ralf Mueller", 0, "rlaf@bj-ig.de" ); + aboutData.addAuthor( "Hamish Rodda", 0, "rodda@kde.org" ); + aboutData.addAuthor( "Torsten Kasch", I18N_NOOP( "Solaris Support\n" + "Parts derived (by permission) from the sunos5\n" + "module of William LeFebvre's \"top\" utility." ), + "tk@Genetik.Uni-Bielefeld.DE" ); + + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( options ); + + KApplication::disableAutoDcopRegistration(); + // initialize KDE application + KApplication *app = new KApplication; + + KSGRD::SensorMgr = new KSGRD::SensorManager(); + KSGRD::Style = new KSGRD::StyleEngine(); + + KCmdLineArgs* args = KCmdLineArgs::parsedArgs(); + + int result = 0; + + if ( args->isSet( "showprocesses" ) ) { + /* To avoid having multiple instances of ksysguard in + * taskmanager mode we check if another taskmanager is running + * already. If so, we terminate this one immediately. */ + if ( app->dcopClient()->registerAs( "ksysguard_taskmanager", false ) == + "ksysguard_taskmanager" ) { + // We have registered with DCOP, our parent can exit now. + char c = 0; + write( initpipe[ 1 ], &c, 1 ); + close( initpipe[ 1 ] ); + + topLevel = new TopLevel( "KSysGuard" ); + topLevel->beATaskManager(); + topLevel->initStatusBar(); + topLevel->show(); + KSGRD::SensorMgr->setBroadcaster( topLevel ); + + // run the application + result = app->exec(); + } else { + QByteArray data; + app->dcopClient()->send( "ksysguard_taskmanager", "KSysGuardIface", + "showOnCurrentDesktop()", data ); + } + } else { + app->dcopClient()->registerAs( "ksysguard" ); + app->dcopClient()->setDefaultObject( "KSysGuardIface" ); + + // We have registered with DCOP, our parent can exit now. + char c = 0; + write( initpipe[ 1 ], &c, 1 ); + close( initpipe[ 1 ] ); + + topLevel = new TopLevel( "KSysGuard" ); + + // create top-level widget + if ( args->count() > 0 ) { + /* The user has specified a list of worksheets to load. In this + * case we do not restore any previous settings but load all the + * requested worksheets. */ + topLevel->showRequestedSheets(); + for ( int i = 0; i < args->count(); ++i ) + topLevel->loadWorkSheet( args->arg( i ) ); + } else { + if ( app->isRestored() ) + topLevel->restore( 1 ); + else + topLevel->readProperties( app->config() ); + } + + topLevel->initStatusBar(); + topLevel->show(); + KSGRD::SensorMgr->setBroadcaster( topLevel ); + + // run the application + result = app->exec(); + } + + delete KSGRD::Style; + delete KSGRD::SensorMgr; + delete app; + + return result; +} + +#include "ksysguard.moc" diff --git a/ksysguard/gui/ksysguard.desktop b/ksysguard/gui/ksysguard.desktop new file mode 100644 index 000000000..76a960ec4 --- /dev/null +++ b/ksysguard/gui/ksysguard.desktop @@ -0,0 +1,102 @@ +[Desktop Entry] +Name=KSysGuard +Name[af]=Ksysguard +Name[ar]=حارس النظام +Name[bg]=Системна защита +Name[csb]=KDE Wachtôrz Systemë +Name[de]=Systemüberwachung +Name[eo]=KSistemGardilo +Name[et]=Süsteemi valvur +Name[fr]=Surveillance du système +Name[he]=משמר המערכת +Name[hi]=के-सिस-गार्ड +Name[hr]=KDE zaštitnik sustava +Name[is]=KDE álagsmælir +Name[ja]=KDE システムガード +Name[lo]=ກວດສອບແລະປ້ອງກັນລະບົບ - K +Name[mn]=Системийн хяналт +Name[nb]=KDE Systemvakt +Name[ne]=KSys रक्षक +Name[nn]=KDE Systemvakt +Name[nso]=Thlokomelo ya KSys +Name[pl]=KDE Strażnik Systemu +Name[sk]=KDE Strážca systému +Name[sv]=Systemövervakare +Name[tg]=Муҳофизати системаи-K +Name[th]=ตรวจสอบและป้องกันระบบ +Name[uz]=KDE tizim nazoratchisi +Name[uz@cyrillic]=KDE тизим назоратчиси +Name[vi]=Bảo vệ Hệ thống KDE +Name[wa]=KSisGåde +GenericName=Performance Monitor +GenericName[af]=Werkverrigting Monitor +GenericName[ar]=مراقب الإداء +GenericName[be]=Сістэмны назіральнік +GenericName[bg]=Мониторинг на системата +GenericName[bs]=Monitor performansi +GenericName[ca]=Monitor de rendiment +GenericName[cs]=Monitor výkonu +GenericName[csb]=Mònitor spòroscë +GenericName[da]=Overvågning af ydelse +GenericName[de]=Performancemonitor +GenericName[el]=Επόπτης συστήματος +GenericName[eo]=Rendimento Monitoro +GenericName[es]=Monitor de rendimiento +GenericName[et]=Jõudluse monitor +GenericName[eu]=Sistemaren errendimenduaren monitorea +GenericName[fa]=نمایشگر کارایی +GenericName[fi]=Järjestelmän suorituskyvyn monitori +GenericName[fr]=Indicateurs de performance +GenericName[fy]=Prestaasjemonitor +GenericName[gl]=Monitor de Rendemento +GenericName[he]=צג מערכת +GenericName[hr]=Nadzor performansi +GenericName[hu]=Teljesítményfigyelő +GenericName[is]=Afkasta eftirlit +GenericName[it]=Monitor delle prestazioni +GenericName[ja]=パフォーマンスモニター +GenericName[ka]=წარმადობის მონიტორი +GenericName[kk]=Жылдамдылық бақылаушысы +GenericName[km]=កម្មវិធីត្រួតពិនិត្យដំណើរការ +GenericName[lt]=Veiksenos monitorius +GenericName[mk]=Монитор на перформанси +GenericName[ms]=Pemantau Prestasi +GenericName[nb]=Ytelsesovervåker +GenericName[nds]=Leisten-Kieker +GenericName[ne]=सम्पादन मनिटर +GenericName[nl]=Prestatiemonitor +GenericName[nn]=Ytelsesovervakar +GenericName[pa]=ਪਰਦਰਸ਼ਨ ਨਿਗਰਾਨ +GenericName[pl]=Monitor wydajności +GenericName[pt]=Monitor de Performance +GenericName[pt_BR]=Monitor de Performance +GenericName[ro]=Monitor de performanță +GenericName[ru]=Монитор производительности +GenericName[rw]=Mugaragaza y'Imikorere +GenericName[se]=Buvttogoziheaddji +GenericName[sk]=Sledovač výkonu +GenericName[sl]=Nadzor delovanja +GenericName[sr]=Монитор перформанси +GenericName[sr@Latn]=Monitor performansi +GenericName[sv]=Prestandaövervakare +GenericName[ta]=செயல்திறன் திரை +GenericName[th]=สอดส่องประสิทธิภาพการทำงานของระบบ +GenericName[tr]=Sistem İzleyici +GenericName[tt]=Citezlek Küzätüçese +GenericName[uk]=Монітор швидкодії +GenericName[uz]=Tizimni nazorat qilish +GenericName[uz@cyrillic]=Тизимни назорат қилиш +GenericName[vi]=Theo dõi Hiệu năng +GenericName[wa]=Corwaitoe di ç' ki va bén +GenericName[zh_CN]=性能监视器 +GenericName[zh_TW]=效能監視器 +Exec=ksysguard %U +Icon=ksysguard +Type=Application +MimeType=application/x-ksysguard; +DocPath=ksysguard/index.html +Terminal=false +Path= +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;System; diff --git a/ksysguard/gui/ksysguard.h b/ksysguard/gui/ksysguard.h new file mode 100644 index 000000000..8d2ef15d9 --- /dev/null +++ b/ksysguard/gui/ksysguard.h @@ -0,0 +1,124 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + + KSysGuard is currently maintained by Chris Schlaeger <cs@kde.org>. Please do + not commit any changes without consulting me first. Thanks! + +*/ + +#ifndef KSG_KSYSGUARD_H +#define KSG_KSYSGUARD_H + +#include <qevent.h> + +#include <dcopclient.h> +#include <dcopobject.h> +#include <kapplication.h> +#include <kmainwindow.h> +#include <dnssd/servicebrowser.h> + +#include <ksgrd/SensorClient.h> + +class KRecentFilesAction; +class KToggleAction; + +class QSplitter; +class SensorBrowser; +class Workspace; + +class TopLevel : public KMainWindow, public KSGRD::SensorClient, public DCOPObject +{ + Q_OBJECT + K_DCOP + + public: + TopLevel( const char *name = 0 ); + + virtual void saveProperties( KConfig* ); + virtual void readProperties( KConfig* ); + + virtual void answerReceived( int id, const QString& ); + + void beATaskManager(); + void showRequestedSheets(); + void initStatusBar(); + + k_dcop: + // calling ksysguard with kwin/kicker hot-key + ASYNC showProcesses(); + ASYNC showOnCurrentDesktop(); + ASYNC loadWorkSheet( const QString &fileName ); + ASYNC removeWorkSheet( const QString &fileName ); + QStringList listHosts(); + QStringList listSensors( const QString &hostName ); + QString readIntegerSensor( const QString &sensorLocator ); + QStringList readListSensor( const QString &sensorLocator ); + + public slots: + void registerRecentURL( const KURL &url ); + void resetWorkSheets(); + + protected: + virtual void customEvent( QCustomEvent* ); + virtual void timerEvent( QTimerEvent* ); + virtual bool queryClose(); + + protected slots: + void connectHost(); + void disconnectHost(); + void updateStatusBar(); + void editToolbars(); + void editStyle(); + void slotNewToolbarConfig(); + void serviceAdded(DNSSD::RemoteService::Ptr srv); + + private: + void setSwapInfo( long, long, const QString& ); + + QPtrList<DCOPClientTransaction> mDCopFIFO; + + QSplitter* mSplitter; + KRecentFilesAction* mActionOpenRecent; + + SensorBrowser* mSensorBrowser; + Workspace* mWorkSpace; + + DNSSD::ServiceBrowser* mServiceBrowser; + + bool mDontSaveSession; + int mTimerId; +}; + +extern TopLevel* Toplevel; + +/* + since there is only a forward declaration of DCOPClientTransaction + in dcopclient.h we have to redefine it here, otherwise QPtrList + causes errors +*/ +typedef unsigned long CARD32; + +class DCOPClientTransaction +{ + public: + Q_INT32 id; + CARD32 key; + QCString senderId; +}; + +#endif diff --git a/ksysguard/gui/ksysguardapplet.desktop b/ksysguard/gui/ksysguardapplet.desktop new file mode 100644 index 000000000..08441fe64 --- /dev/null +++ b/ksysguard/gui/ksysguardapplet.desktop @@ -0,0 +1,120 @@ +[Desktop Entry] +Type=Plugin +Name=System Guard +Name[af]=Stelsel Wag +Name[ar]=حارس النظام +Name[be]=Сістэмны ахоўнік +Name[bg]=Системен монитор +Name[bn]=সিস্টেম প্রহরী +Name[br]=Gward Reizhiad +Name[bs]=Nadzor sistema +Name[ca]=Vigilant del sistema +Name[cs]=Strážce systému +Name[csb]=Wachtôrz Systemë +Name[da]=Systemvagt +Name[de]=Systemüberwachung +Name[el]=Φρουρός συστήματος +Name[eo]=Sistemo Gardilo +Name[es]=Guardián del sistema +Name[et]=Süsteemi valvur +Name[eu]=Sistemaren zaintzailea +Name[fa]=محافظ سیستم +Name[fi]=Järjestelmän valvonta +Name[fr]=Surveillance du système +Name[fy]=Systeemwarder +Name[gl]=Vixiante do Sistema +Name[he]=משמר המערכת +Name[hr]=Zaštitnik sustava +Name[hu]=Rendszermonitor +Name[is]=Kerfiseftirlit +Name[it]=Controllo del sistema +Name[ja]=システムガード +Name[ka]=სისტემის მცველი +Name[kk]=Жүйе бақылаушысы +Name[km]=ឆ្មាំប្រព័ន្ធ +Name[ko]=KDE 시스템 지킴이 +Name[lt]=Sistemos apsauga +Name[mk]=Чувар на системот +Name[nb]=Systemvakt +Name[nds]=Systeemwachter +Name[ne]=प्रणाली रक्षक +Name[nl]=Systeembewaking +Name[nn]=Systemvakt +Name[pa]=ਸਿਸਟਮ ਗਾਰਡ +Name[pl]=Strażnik Systemu +Name[pt]=Vigilante do Sistema +Name[pt_BR]=Guarda do Sistema +Name[ro]=Sistem de gardă +Name[ru]=Системный монитор +Name[se]=Vuogádatfákta +Name[sk]=Strážca systému +Name[sl]=Sistemski varuh +Name[sr]=Заштита система +Name[sr@Latn]=Zaštita sistema +Name[sv]=Systemövervakare +Name[th]=ป้องกันระบบ +Name[tr]=Sistem İzleyici +Name[uk]=Системний вартовий +Name[uz]=Kengaytirilgan tizim nazoratchisi +Name[uz@cyrillic]=Кенгайтирилган тизим назоратчиси +Name[vi]=Bảo vệ Hệ thống +Name[wa]=Gåde do sistinme +Name[zh_CN]=系统卫士 +Name[zh_TW]=系統守衛 +Comment=An advanced system monitor which swallows KDE system guard displays +Comment[af]='n Gevorderde stelsel monitor wat KDE se stelsel wag skerms insluit +Comment[be]=Адмысловы сістэмны назіральнік, які "праглынае" дысплеі сістэмнага ахоўніка KDE +Comment[bg]=Системен монитор, който следи за състоянието на системата +Comment[bs]=Napredni program za nadzor sistema koji obuhvata više drugih prozora +Comment[ca]=Un monitor del sistema avançat que inclou pantalles del vigilant del sistema KDE +Comment[cs]=Pokročilý monitor systému, který pohlcuje displeje strážce KDE +Comment[csb]=Awansowóny mònitor systemë jaczi pòkazywô wskôzywôcze KDE Wachtôrza Systemë +Comment[da]=En avanceret systemovervåger som svælger skærme fra KDE's systemovervågning +Comment[de]=Erweiterte Systemüberwachung für die Kontrollleiste +Comment[el]=Ένας προχωρημένος επόπτης του συστήματος ο οποίος ενσωματώνει προβολές του φρουρού συστήματος του KDE +Comment[eo]=Malbaza sistemomonitoro kiu glutas KDE-sistemogardilo-ekranojn. +Comment[es]=Un monitor avanzado del sistema que integra los gráficos del guardián del sistema de KDE +Comment[et]=Võimas süsteemi monitor KDE süsteemi valvuri sensoritele +Comment[eu]=Sistema monitore aurreratua, KDE sistemaren zaintzailearen pantailak bistaratzen dituena +Comment[fa]=یک نمایشگر پیشرفتۀ سیستم که نمایشهای محافظ سیستم KDE را از بین میبرد +Comment[fi]=Edistynyt järjestelmän valvonta, johon sisältyy KDE järjestelmänvalvonnan näytöt +Comment[fr]=Un surveillant avancé affichant l'état du système +Comment[fy]=In avansearre systeemmonitor mei systeemwardings werjefte +Comment[gl]=Un monitor do sistema que incorpora os resultados do vixiante do sistema de KDE +Comment[he]=מנטר מערכת מתקדם המאפשר המטעה של תצוגות של משמר המערכת של KDE +Comment[hr]=Napredan sistemski nadzor koji "guta" prikaze KDE zaštitnika sustava +Comment[hu]=Rendszermonitor kijelzőkkel +Comment[is]=Þróað kerfiseftirlit sem gleypir KDE álagsmæla +Comment[it]=Un sistema di controllo del sistema avanzato che ingloba i controlli di sistema di KDE +Comment[ja]=KDE システムガードを表示する高度なシステムモニター +Comment[kk]=Жетілдірілген жүйе бақылаушысы +Comment[km]=កម្មវិធីត្រួតពិនិត្យប្រព័ន្ធកម្រិតខ្ពស់ដែលអនុញ្ញាតឲ្យប្រព័ន្ធ KDE ត្រួតពិនិត្យការបង្ហាញ +Comment[lt]=Sudėtingesnė sistemos stebėjimo priemonė, įtraukianti KDE sistemos apsaugos stebėjimo priemones +Comment[mk]=Напреден монитор на системот кој ги врамува приказите на чуварите на системот на KDE +Comment[nb]=En avansert systemovervåker som svelger visninger av KDEs systemovervåker +Comment[nds]=En verwiedert Systeemkieker, mit inbett Diagrammen vun KDE System Guard +Comment[ne]=उन्नत प्रणाली मनिटर जसले अन्त्य गर्ने KDE प्रणाली रक्षक प्रदर्शन गर्छ +Comment[nl]=Een geavanceerde systeemmonitor met systeembewakingsdisplays +Comment[nn]=Ein avansert systemovervakar som svelgjer visingar av KDE-systemovervakaren +Comment[pl]=Zaawansowany monitor systemu pokazujący wskaźniki Strażnika systemu KDE +Comment[pt]=Um monitor de sistema avançado que engloba folhas de monitorização do sistema KDE +Comment[pt_BR]=Um monitor avançado de sistema que permite monitorar o que a guarda do sistema do KDE exibe +Comment[ro]=Un monitor de sistem avansat care înghite ecranele sistemului de gardă KDE +Comment[ru]=Системный монитор +Comment[sk]=Sledovač systému, ktorý obsahuje systémových strážcov KDE +Comment[sl]=Napreden nadzor sistema, ki uporablja prikazovalnike iz Sistemskega varuha KDE +Comment[sr]=Напредни монитор који гута приказе KDE-ове заштите система +Comment[sr@Latn]=Napredni monitor koji guta prikaze KDE-ove zaštite sistema +Comment[sv]=En avancerad systemövervakare som sväljer skärmar från KDE:s systemövervakare +Comment[th]=ตัวเฝ้าตรวจสอบระบบขั้นก้าวหน้า ซึ่งกลืนหน้าจอของตัวป้องกันระบบ KDE +Comment[tr]=Gelişmiş bir sistem izleyici +Comment[uk]=Додатковий системний монітор, який поглинає показ системного вартового KDE +Comment[uz]=Tizimning protsessor, xotira, tarmoq kabi qisimlarini kuzatib turadigan kengaytirilgan tizim nazoratchisi +Comment[uz@cyrillic]=Тизимнинг процессор, хотира, тармоқ каби қисимларини кузатиб турадиган кенгайтирилган тизим назоратчиси +Comment[vi]=Một trình theo dõi hệ thống nâng cao thế chỗ cho hiển thị bảo vệ hệ thống KDE +Comment[wa]=On corwaitoe po les spepieus k' avale li håynaedje so gåde do sistinme di KDE +Comment[zh_CN]=可显示 KDE 系统卫士效果的高级系统监视器 +Comment[zh_TW]=包含 KDE 系統守衛顯示的進階系統監視器 +Icon=ksysguard +X-KDE-Library=sysguard_panelapplet +X-KDE-UniqueApplet=true diff --git a/ksysguard/gui/ksysguardui.rc b/ksysguard/gui/ksysguardui.rc new file mode 100644 index 000000000..912894ed3 --- /dev/null +++ b/ksysguard/gui/ksysguardui.rc @@ -0,0 +1,50 @@ +<!DOCTYPE kpartgui> +<kpartgui name="ksysguard" version="5"> +<State name="showProcessState"> + <Disable> + <Action name="new_worksheet"/> + <Action name="import_worksheet"/> + <Action name="recent_import_worksheet"/> + <Action name="export_worksheet"/> + <Action name="remove_worksheet"/> + <Action name="revert_all_worksheets"/> + <Action name="connect_host"/> + <Action name="disconnect_host"/> + <Action name="configure_sheet"/> + <Action name="configure_style"/> + </Disable> +</State> +<MenuBar> + <Menu name="file"><text>&File</text> + <Action name="new_worksheet"/> + <Action name="recent_import_worksheet"/> + <Action name="import_worksheet"/> + <Separator/> + <Action name="export_worksheet"/> + <Separator/> + <Action name="remove_worksheet"/> + <Action name="revert_all_worksheets"/> + <Separator/> + <Action name="connect_host"/> + <Action name="disconnect_host"/> + </Menu> + <Menu name="edit"><text>&Edit</text> + <Action name="configure_sheet"/> + </Menu> + <Menu name="settings"><text>&Settings</text> + <Action name="configure_style"/> + </Menu> +</MenuBar> +<ToolBar name="mainToolBar" noMerge="1"><text>Main Toolbar</text> + <Action name="new_worksheet"/> + <Action name="import_worksheet"/> + <Action name="export_worksheet"/> + <Separator/> + <Action name="connect_host"/> + <Action name="disconnect_host"/> + <Separator/> + <Action name="configure_sheet"/> + <Action name="configure_style"/> +</ToolBar> +</kpartgui> + diff --git a/ksysguard/gui/x-ksysguard.desktop b/ksysguard/gui/x-ksysguard.desktop new file mode 100644 index 000000000..78a0a15c9 --- /dev/null +++ b/ksysguard/gui/x-ksysguard.desktop @@ -0,0 +1,86 @@ +# KDE Config File +[Desktop Entry] +NotShowIn=GNOME; +MimeType=application/x-ksysguard +Comment=KDE System Guard +Comment[af]=KDE Stelsel Wag +Comment[ar]=حارس النظام KDE +Comment[az]=KDE Sistem Cangüdəni +Comment[be]=Ахоўнік сістэмы KDE +Comment[bg]=Системна защита +Comment[bn]=কে.ডি.ই. সিস্টেম গার্ড +Comment[br]=Gward Reizhiad KDE +Comment[bs]=KDE zaštita sistema +Comment[ca]=Vigilant del sistema KDE +Comment[cs]=Správce systému KDE +Comment[csb]=KDE Wachtôrz Systemë +Comment[cy]=Gwarchodwr Cysawd KDE +Comment[da]=KDE Systemvagt +Comment[de]=KDE-Systemüberwachung +Comment[el]=Φρουρός συστήματος του KDE +Comment[eo]=KDE-Sistemobservilo +Comment[es]=Guardián del sistema de KDE +Comment[et]=KDE süsteemi valvur +Comment[eu]=KDEren sistemaren kontrola +Comment[fa]=محافظ سیستم KDE +Comment[fi]=KDE:n järjestelmänvalvonta +Comment[fr]=Surveillance du système +Comment[fy]=KDE systeembefeiliging +Comment[ga]=Garda an Chórais KDE +Comment[gl]=Vixiante do Sistema de KDE +Comment[he]=משמר המערכת של KDE +Comment[hi]=केडीई तंत्र गार्ड +Comment[hr]=KDE zaštitnik sustava +Comment[hu]=KDE rendszermonitor +Comment[is]=KDE kerfisvörður +Comment[it]=Controllo di sistema di KDE +Comment[ja]=KDE システムガード +Comment[ka]=KDE სისტემური მონიტორი +Comment[kk]=KDE жүйелік бақылаушысы +Comment[km]=ការពារប្រព័ន្ធ KDE +Comment[ko]=KDE 시스템 지킴이 +Comment[lo]=ເຄື່ອງມືຶປ້ອງກັນລະບົບຂອງ KDE +Comment[lt]=KDE sistemos apsauga +Comment[lv]=KDE Sistēmas Sargs +Comment[mk]=KDE Системски чувар +Comment[mn]=КДЭ-Системийн хяналт +Comment[ms]=Pengawas Sistem KDE +Comment[mt]=Gwardja tas-Sistema KDE +Comment[nb]=KDE Systemovervåker +Comment[nds]=KDE-Systeemwachter +Comment[ne]=KDE प्रणाली रक्षक +Comment[nl]=KDE systeembewaking +Comment[nn]=KDE Systemvakt +Comment[nso]=Thlokomelo ya System ya KDE +Comment[pa]=KDE ਸਿਸਟਮ ਗਾਰਡ +Comment[pl]=KDE Strażnik Systemu +Comment[pt]=Vigilante do sistema do KDE +Comment[pt_BR]=Sistema de Guarda do KDE +Comment[ro]=Sistem de gardă KDE +Comment[ru]=Системный монитор +Comment[rw]=Umurinzi Sisitemu KDE +Comment[se]=KDE vuogádatfákta +Comment[sk]=KDE Strážca systému +Comment[sl]=Sistemski varuh KDE +Comment[sr]=KDE чувар система +Comment[sr@Latn]=KDE čuvar sistema +Comment[sv]=KDE:s systemövervakare +Comment[ta]=KDE கணினி காவலன் +Comment[tg]=Муҳофизи системаи KDE +Comment[th]=เครื่องมือป้องกันระบบ KDE +Comment[tr]=KDE Sistem Koruyucu +Comment[tt]=KDE'nıñ Sistem Saqçısı +Comment[uk]=Системний вартовий KDE +Comment[uz]=KDE tizim nazoratchisi +Comment[uz@cyrillic]=KDE тизим назоратчиси +Comment[ven]=Mulindi wa maitele a KDE +Comment[vi]=Trình bảo vệ Hệ thống KDE +Comment[wa]=Gåre sistinme KDE +Comment[xh]=KDE Ukhuselo lendlela yokusebenza +Comment[zh_CN]=KDE 系统卫士 +Comment[zh_TW]=KDE 系統守衛 +Comment[zu]=Unogada Wesistimu ye-KDE +Icon=ksysguard +Type=MimeType +Patterns=*.sgrd; +X-KDE-AutoEmbed=false diff --git a/ksysguard/ksysguardd/Command.c b/ksysguard/ksysguardd/Command.c new file mode 100644 index 000000000..17abffb92 --- /dev/null +++ b/ksysguard/ksysguardd/Command.c @@ -0,0 +1,261 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@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 <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> + +#include "ccont.h" +#include "ksysguardd.h" + +#include "Command.h" + +typedef struct { + char* command; + cmdExecutor ex; + char* type; + int isMonitor; + struct SensorModul* sm; +} Command; + +static CONTAINER CommandList; +static sigset_t SignalSet; + +void command_cleanup( void* v ); + +void command_cleanup( void* v ) +{ + if ( v ) { + Command* c = v; + if ( c->command ) + free ( c->command ); + if ( c->type ) + free ( c->type ); + free ( v ); + } +} + +/* +================================ public part ================================= +*/ + +int ReconfigureFlag = 0; +int CheckSetupFlag = 0; + +void print_error( const char *fmt, ... ) +{ + char errmsg[ 1024 ]; + va_list az; + + va_start( az, fmt ); + vsnprintf( errmsg, sizeof( errmsg ) - 1, fmt, az ); + errmsg[ sizeof( errmsg ) - 1 ] = '\0'; + va_end( az ); + + if ( CurrentClient ) + fprintf( CurrentClient, "\033%s\033", errmsg ); +} + +void log_error( const char *fmt, ... ) +{ + char errmsg[ 1024 ]; + va_list az; + + va_start( az, fmt ); + vsnprintf( errmsg, sizeof( errmsg ) - 1, fmt, az ); + errmsg[ sizeof( errmsg ) - 1 ] = '\0'; + va_end( az ); + + openlog( "ksysguardd", LOG_PID, LOG_DAEMON ); + syslog( LOG_ERR, "%s", errmsg ); + closelog(); +} + +void initCommand( void ) +{ + CommandList = new_ctnr(); + sigemptyset( &SignalSet ); + sigaddset( &SignalSet, SIGALRM ); + + registerCommand( "monitors", printMonitors ); + registerCommand( "test", printTest ); + + if ( RunAsDaemon == 0 ) + registerCommand( "quit", exQuit ); +} + +void exitCommand( void ) +{ + destr_ctnr( CommandList, command_cleanup ); +} + +void registerCommand( const char* command, cmdExecutor ex ) +{ + Command* cmd = (Command*)malloc( sizeof( Command ) ); + cmd->command = (char*)malloc( strlen( command ) + 1 ); + strcpy( cmd->command, command ); + cmd->type = 0; + cmd->ex = ex; + cmd->isMonitor = 0; + push_ctnr( CommandList, cmd ); + ReconfigureFlag = 1; +} + +void removeCommand( const char* command ) +{ + Command* cmd; + + for ( cmd = first_ctnr( CommandList ); cmd; cmd = next_ctnr( CommandList ) ) { + if ( strcmp( cmd->command, command ) == 0 ) { + remove_ctnr( CommandList ); + if ( cmd->command ) + free( cmd->command ); + if ( cmd->type ) + free( cmd->type ); + free( cmd ); + } + } + + ReconfigureFlag = 1; +} + +void registerMonitor( const char* command, const char* type, cmdExecutor ex, + cmdExecutor iq, struct SensorModul* sm ) +{ + /* Monitors are similar to regular commands except that every monitor + * registers two commands. The first is the value request command and + * the second is the info request command. The info request command is + * identical to the value request but with an '?' appended. The value + * command prints a single value. The info request command prints + * a description of the monitor, the mininum value, the maximum value + * and the unit. */ + Command* cmd = (Command*)malloc( sizeof( Command ) ); + cmd->command = (char*)malloc( strlen( command ) + 1 ); + strcpy( cmd->command, command ); + cmd->ex = ex; + cmd->type = (char*)malloc( strlen( type ) + 1 ); + strcpy( cmd->type, type ); + cmd->isMonitor = 1; + cmd->sm = sm; + push_ctnr( CommandList, cmd ); + + cmd = (Command*)malloc( sizeof( Command ) ); + cmd->command = (char*)malloc( strlen( command ) + 2 ); + strcpy( cmd->command, command ); + cmd->command[ strlen( command ) ] = '?'; + cmd->command[ strlen( command ) + 1 ] = '\0'; + cmd->ex = iq; + cmd->isMonitor = 0; + cmd->sm = sm; + cmd->type = 0; + push_ctnr( CommandList, cmd ); +} + +void removeMonitor( const char* command ) +{ + char* buf; + + removeCommand( command ); + buf = (char*)malloc( strlen( command ) + 2 ); + strcpy( buf, command ); + strcat( buf, "?" ); + removeCommand( buf ); + free( buf ); +} + +void executeCommand( const char* command ) +{ + Command* cmd; + char tokenFormat[ 64 ]; + char token[ 64 ]; + + sprintf( tokenFormat, "%%%ds", (int)sizeof( token ) - 1 ); + sscanf( command, tokenFormat, token ); + + for ( cmd = first_ctnr( CommandList ); cmd; cmd = next_ctnr( CommandList ) ) { + if ( strcmp( cmd->command, token ) == 0 ) { + if ( cmd->isMonitor ) { + if ( ( time( NULL ) - cmd->sm->time ) >= UPDATEINTERVAL ) { + cmd->sm->time = time( NULL ); + + if ( cmd->sm->updateCommand != NULL ) + cmd->sm->updateCommand(); + } + } + + (*(cmd->ex))( command ); + + if ( ReconfigureFlag ) { + ReconfigureFlag = 0; + print_error( "RECONFIGURE\n" ); + } + + fflush( CurrentClient ); + return; + } + } + + if ( CurrentClient ) { + fprintf( CurrentClient, "UNKNOWN COMMAND\n" ); + fflush( CurrentClient ); + } +} + +void printMonitors( const char *c ) +{ + Command* cmd; + ReconfigureFlag = 0; + + (void)c; + + for ( cmd = first_ctnr( CommandList ); cmd; cmd = next_ctnr( CommandList ) ) { + if ( cmd->isMonitor ) + fprintf(CurrentClient, "%s\t%s\n", cmd->command, cmd->type); + } + + fflush( CurrentClient ); +} + +void printTest( const char* c ) +{ + Command* cmd; + + for ( cmd = first_ctnr( CommandList ); cmd; cmd = next_ctnr( CommandList ) ) { + if ( strcmp( cmd->command, c + strlen( "test " ) ) == 0 ) { + fprintf( CurrentClient, "1\n" ); + fflush( CurrentClient ); + return; + } + } + + fprintf( CurrentClient, "0\n" ); + fflush( CurrentClient ); +} + +void exQuit( const char* cmd ) +{ + (void)cmd; + + QuitApp = 1; +} diff --git a/ksysguard/ksysguardd/Command.h b/ksysguard/ksysguardd/Command.h new file mode 100644 index 000000000..d3645d905 --- /dev/null +++ b/ksysguard/ksysguardd/Command.h @@ -0,0 +1,103 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@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 "ksysguardd.h" + +#ifndef KSG_COMMAND_H +#define KSG_COMMAND_H + +typedef void (*cmdExecutor)(const char*); + +/** + Set this flag to '1' to request a rescan of the available sensors + in the front end. + */ +extern int ReconfigureFlag; + +/** + Has nearly the same meaning like the above flag ;) + */ +extern int CheckSetupFlag; + +/** + Delivers the error message to the front end. + */ +void print_error( const char*, ... ) +#ifdef __GNUC__ + __attribute__ ( ( format ( printf, 1, 2 ) ) ) +#endif + ; + +/** + Writes the error message to the syslog daemon. + */ +void log_error( const char*, ... ) + #ifdef __GNUC__ + __attribute__ ( ( format ( printf, 1, 2 ) ) ) +#endif + ; + + + +/** + Use this function to register a command with the name + @ref command and the function pointer @ref ex. + */ +void registerCommand( const char* command, cmdExecutor ex ); + +/** + Use this function to remove a command with the name + @ref command. + */ +void removeCommand( const char* command ); + +/** + Use this function to add a new montior with the name @ref monitor + from the type @ref type. + @ref ex is a pointer to the function that is called to get a value + and @ref iq is a pointer to the function that returns informations + about this monitor. + @ref sm is a parameter to the sensor modul object that is passed by + the initXXX method. + */ +void registerMonitor( const char* monitor, const char* type, cmdExecutor ex, + cmdExecutor iq, struct SensorModul* sm ); + +/** + Use this function to add the montior with the name @ref monitor. + */ +void removeMonitor( const char* monitor ); + + +/** + Internal usage. + */ +void executeCommand( const char* command ); + +void initCommand( void ); +void exitCommand( void ); + +void printMonitors( const char* cmd ); +void printTest( const char* cmd ); + +void exQuit( const char* cmd ); + +#endif diff --git a/ksysguard/ksysguardd/FreeBSD/CPU.c b/ksysguard/ksysguardd/FreeBSD/CPU.c new file mode 100644 index 000000000..90d0c4721 --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/CPU.c @@ -0,0 +1,263 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@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 <osreldate.h> + +#include <sys/types.h> +#if defined(__DragonFly__) +#include <sys/param.h> +#include <kinfo.h> +#elif __FreeBSD_version < 500101 + #include <sys/dkstat.h> +#else + #include <sys/resource.h> +#endif +#include <sys/sysctl.h> + +#include <devstat.h> +#include <fcntl.h> +#include <nlist.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "CPU.h" +#include "Command.h" +#include "ksysguardd.h" + +#if defined(__DragonFly__) +static void cputime_percentages(int[4], struct kinfo_cputime *, + struct kinfo_cputime *); +static struct kinfo_cputime cp_time, cp_old; + +#define CPUSTATES 4 +#define CP_USER 0 +#define CP_NICE 1 +#define CP_SYS 2 +#define CP_IDLE 3 + +#else +long percentages(int cnt, int *out, long *new, long *old, long *diffs); + +unsigned long cp_time_offset; + +long cp_time[CPUSTATES]; +long cp_old[CPUSTATES]; +long cp_diff[CPUSTATES]; +#endif + +int cpu_states[CPUSTATES]; + +void +initCpuInfo(struct SensorModul* sm) +{ + /* Total CPU load */ + registerMonitor("cpu/user", "integer", printCPUUser, + printCPUUserInfo, sm); + registerMonitor("cpu/nice", "integer", printCPUNice, + printCPUNiceInfo, sm); + registerMonitor("cpu/sys", "integer", printCPUSys, + printCPUSysInfo, sm); + registerMonitor("cpu/idle", "integer", printCPUIdle, + printCPUIdleInfo, sm); + + updateCpuInfo(); +} + +void +exitCpuInfo(void) +{ +} + +int +updateCpuInfo(void) +{ +#if defined(__DragonFly__) + kinfo_get_sched_cputime(&cp_time); + cputime_percentages(cpu_states, &cp_time, &cp_old); +#else + size_t len = sizeof(cp_time); + sysctlbyname("kern.cp_time", &cp_time, &len, NULL, 0); + percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); +#endif + return (0); +} + +void +printCPUUser(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", cpu_states[CP_USER]/10); +} + +void +printCPUUserInfo(const char* cmd) +{ + fprintf(CurrentClient, "CPU User Load\t0\t100\t%%\n"); +} + +void +printCPUNice(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", cpu_states[CP_NICE]/10); +} + +void +printCPUNiceInfo(const char* cmd) +{ + fprintf(CurrentClient, "CPU Nice Load\t0\t100\t%%\n"); +} + +void +printCPUSys(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", cpu_states[CP_SYS]/10); +} + +void +printCPUSysInfo(const char* cmd) +{ + fprintf(CurrentClient, "CPU System Load\t0\t100\t%%\n"); +} + +void +printCPUIdle(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", cpu_states[CP_IDLE]/10); +} + +void +printCPUIdleInfo(const char* cmd) +{ + fprintf(CurrentClient, "CPU Idle Load\t0\t100\t%%\n"); +} + + +/* The part ripped from top... */ +/* + * Top users/processes display for Unix + * Version 3 + * + * This program may be freely redistributed, + * but this entire comment MUST remain intact. + * + * Copyright (c) 1984, 1989, William LeFebvre, Rice University + * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University + */ + +/* + * percentages(cnt, out, new, old, diffs) - calculate percentage change + * between array "old" and "new", putting the percentages i "out". + * "cnt" is size of each array and "diffs" is used for scratch space. + * The array "old" is updated on each call. + * The routine assumes modulo arithmetic. This function is especially + * useful on BSD mchines for calculating cpu state percentages. + */ +#if defined(__DragonFly__) +static void +cputime_percentages(int out[4], struct kinfo_cputime *new, struct kinfo_cputime * old) +{ + struct kinfo_cputime diffs; + int i; + uint64_t total_change, half_total; + + /* initialization */ + total_change = 0; + + diffs.cp_user = new->cp_user - old->cp_user; + diffs.cp_nice = new->cp_nice - old->cp_nice; + diffs.cp_sys = new->cp_sys - old->cp_sys; + diffs.cp_intr = new->cp_intr - old->cp_intr; + diffs.cp_idle = new->cp_idle - old->cp_idle; + total_change = diffs.cp_user + diffs.cp_nice + diffs.cp_sys + + diffs.cp_intr + diffs.cp_idle; + old->cp_user = new->cp_user; + old->cp_nice = new->cp_nice; + old->cp_sys = new->cp_sys; + old->cp_intr = new->cp_intr; + old->cp_idle = new->cp_idle; + + /* avoid divide by zero potential */ + if (total_change == 0) + total_change = 1; + + /* calculate percentages based on overall change, rounding up */ + half_total = total_change >> 1; + + out[0] = ((diffs.cp_user * 1000LL + half_total) / total_change); + out[1] = ((diffs.cp_nice * 1000LL + half_total) / total_change); + out[2] = (((diffs.cp_sys + diffs.cp_intr) * 1000LL + half_total) / total_change); + out[4] = ((diffs.cp_idle * 1000LL + half_total) / total_change); +} + +#else +long percentages(cnt, out, new, old, diffs) + +int cnt; +int *out; +register long *new; +register long *old; +long *diffs; + +{ + register int i; + register long change; + register long total_change; + register long *dp; + long half_total; + + /* initialization */ + total_change = 0; + dp = diffs; + + /* calculate changes for each state and the overall change */ + for (i = 0; i < cnt; i++) + { + if ((change = *new - *old) < 0) + { + /* this only happens when the counter wraps */ + change = (int) + ((unsigned long)*new-(unsigned long)*old); + } + total_change += (*dp++ = change); + *old++ = *new++; + } + + /* avoid divide by zero potential */ + if (total_change == 0) + { + total_change = 1; + } + + /* calculate percentages based on overall change, rounding up */ + half_total = total_change / 2l; + + /* Do not divide by 0. Causes Floating point exception */ + if(total_change) { + for (i = 0; i < cnt; i++) + { + *out++ = (int)((*diffs++ * 1000 + half_total) / total_change); + } + } + + /* return the total in case the caller wants to use it */ + return(total_change); +} +#endif diff --git a/ksysguard/ksysguardd/FreeBSD/CPU.h b/ksysguard/ksysguardd/FreeBSD/CPU.h new file mode 100644 index 000000000..c35932ac8 --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/CPU.h @@ -0,0 +1,49 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@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 _cpuinfo_h_ +#define _cpuinfo_h_ + +struct SensorModul; + +void initCpuInfo(struct SensorModul* sm); +void exitCpuInfo(void); + +int updateCpuInfo(void); + +void printCPUUser(const char* cmd); +void printCPUUserInfo(const char* cmd); +void printCPUNice(const char* cmd); +void printCPUNiceInfo(const char* cmd); +void printCPUSys(const char* cmd); +void printCPUSysInfo(const char* cmd); +void printCPUIdle(const char* cmd); +void printCPUIdleInfo(const char* cmd); +void printCPUxUser(const char* cmd); +void printCPUxUserInfo(const char* cmd); +void printCPUxNice(const char* cmd); +void printCPUxNiceInfo(const char* cmd); +void printCPUxSys(const char* cmd); +void printCPUxSysInfo(const char* cmd); +void printCPUxIdle(const char* cmd); +void printCPUxIdleInfo(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/FreeBSD/Makefile.am b/ksysguard/ksysguardd/FreeBSD/Makefile.am new file mode 100644 index 000000000..29860a407 --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/Makefile.am @@ -0,0 +1,8 @@ +# +# + +INCLUDES = -I$(srcdir)/../../CContLib -I$(srcdir)/.. + +noinst_LIBRARIES = libksysguardd.a +libksysguardd_a_SOURCES = CPU.c Memory.c ProcessList.c apm.c diskstat.c \ + loadavg.c logfile.c netdev.c diff --git a/ksysguard/ksysguardd/FreeBSD/Memory.c b/ksysguard/ksysguardd/FreeBSD/Memory.c new file mode 100644 index 000000000..9e3db646c --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/Memory.c @@ -0,0 +1,209 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999-2000 Hans Petter Bieker <bieker@kde.org> + Copyright (c) 1999 Chris Schlaeger <cs@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 <sys/types.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/vmmeter.h> + +#include <vm/vm_param.h> + +#include <fcntl.h> +#include <kvm.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "Command.h" +#include "Memory.h" +#include "ksysguardd.h" + +static size_t Total = 0; +static size_t MFree = 0; +static size_t Used = 0; +static size_t Buffers = 0; +static size_t Cached = 0; +static size_t Application = 0; +static size_t STotal = 0; +static size_t SFree = 0; +static size_t SUsed = 0; +static kvm_t *kd; + +void +initMemory(struct SensorModul* sm) +{ + char *nlistf = NULL; + char *memf = NULL; + char buf[_POSIX2_LINE_MAX]; + + if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == NULL) { + log_error("kvm_openfiles()"); + return; + } + + registerMonitor("mem/physical/free", "integer", printMFree, printMFreeInfo, sm); + registerMonitor("mem/physical/used", "integer", printUsed, printUsedInfo, sm); + registerMonitor("mem/physical/buf", "integer", printBuffers, printBuffersInfo, sm); + registerMonitor("mem/physical/cached", "integer", printCached, printCachedInfo, sm); + registerMonitor("mem/physical/application", "integer", printApplication, printApplicationInfo, sm); + registerMonitor("mem/swap/free", "integer", printSwapFree, printSwapFreeInfo, sm); + registerMonitor("mem/swap/used", "integer", printSwapUsed, printSwapUsedInfo, sm); +} + +void +exitMemory(void) +{ + kvm_close(kd); +} + +int +updateMemory(void) +{ + size_t len; + FILE *file; + char buf[256]; + struct kvm_swap kswap[16]; + int i, swap_count, hlen, pagesize = getpagesize(); + long blocksize; + + len = sizeof (Total); + sysctlbyname("hw.physmem", &Total, &len, NULL, 0); + Total /= 1024; + + /* Borrowed from pstat */ + swap_count = kvm_getswapinfo(kd, kswap, 16, SWIF_DEV_PREFIX); + getbsize(&hlen, &blocksize); + +#define CONVERT(v) ((int)((quad_t)(v) * pagesize / blocksize)) + + if (swap_count > 0) { + STotal = CONVERT(kswap[0].ksw_total); + SUsed = CONVERT(kswap[0].ksw_used); + SFree = CONVERT(kswap[0].ksw_total - kswap[0].ksw_used); + } + + len = sizeof (Buffers); + if ((sysctlbyname("vfs.bufspace", &Buffers, &len, NULL, 0) == -1) || !len) + Buffers = 0; /* Doesn't work under FreeBSD v2.2.x */ + Buffers /= 1024; + + len = sizeof (Cached); + if ((sysctlbyname("vm.stats.vm.v_cache_count", &Cached, &len, NULL, 0) == -1) || !len) + Cached = 0; /* Doesn't work under FreeBSD v2.2.x */ + Cached *= pagesize / 1024; + + len = sizeof (MFree); + if ((sysctlbyname("vm.stats.vm.v_free_count", &MFree, &len, NULL, 0) == -1) || !len) + MFree = 0; /* Doesn't work under FreeBSD v2.2.x */ + MFree *= pagesize / 1024; + + Used = Total - MFree; + Application = Used - Buffers - Cached; + + return 0; +} + +void +printMFree(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", MFree); +} + +void +printMFreeInfo(const char* cmd) +{ + fprintf(CurrentClient, "Free Memory\t0\t%d\tKB\n", Total); +} + +void +printUsed(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", Used); +} + +void +printUsedInfo(const char* cmd) +{ + fprintf(CurrentClient, "Used Memory\t0\t%d\tKB\n", Total); +} + +void +printBuffers(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", Buffers); +} + +void +printBuffersInfo(const char* cmd) +{ + fprintf(CurrentClient, "Buffer Memory\t0\t%d\tKB\n", Total); +} + +void +printCached(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", Cached); +} + +void +printCachedInfo(const char* cmd) +{ + fprintf(CurrentClient, "Cached Memory\t0\t%d\tKB\n", Total); +} + +void +printApplication(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", Application); +} + +void +printApplicationInfo(const char* cmd) +{ + fprintf(CurrentClient, "Application Memory\t0\t%ld\tKB\n", Total); +} + +void +printSwapUsed(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", SUsed); +} + +void +printSwapUsedInfo(const char* cmd) +{ + fprintf(CurrentClient, "Used Swap Memory\t0\t%d\tKB\n", STotal); +} + +void +printSwapFree(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", SFree); +} + +void +printSwapFreeInfo(const char* cmd) +{ + fprintf(CurrentClient, "Free Swap Memory\t0\t%d\tKB\n", STotal); +} diff --git a/ksysguard/ksysguardd/FreeBSD/Memory.h b/ksysguard/ksysguardd/FreeBSD/Memory.h new file mode 100644 index 000000000..66b521617 --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/Memory.h @@ -0,0 +1,45 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@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 _memory_h_ +#define _memory_h_ + +void initMemory(struct SensorModul* sm); +void exitMemory(void); + +int updateMemory(void); + +void printMFree(const char* cmd); +void printMFreeInfo(const char* cmd); +void printUsed(const char* cmd); +void printUsedInfo(const char* cmd); +void printBuffers(const char* cmd); +void printBuffersInfo(const char* cmd); +void printCached(const char* cmd); +void printCachedInfo(const char* cmd); +void printApplication(const char* cmd); +void printApplicationInfo(const char* cmd); +void printSwapUsed(const char* cmd); +void printSwapUsedInfo(const char* cmd); +void printSwapFree(const char* cmd); +void printSwapFreeInfo(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/FreeBSD/ProcessList.c b/ksysguard/ksysguardd/FreeBSD/ProcessList.c new file mode 100644 index 000000000..f8d2c3ba6 --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/ProcessList.c @@ -0,0 +1,556 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999-2000 Hans Petter Bieker<bieker@kde.org> + Copyright (c) 1999 Chris Schlaeger <cs@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 <config.h> + +#include <ctype.h> +#include <dirent.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> + +#if defined(__DragonFly__) +#include <sys/user.h> +#include <sys/resourcevar.h> +#endif + +#if __FreeBSD_version > 500015 +#include <sys/priority.h> +#endif +#include <sys/sysctl.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/user.h> +#include <unistd.h> +#include <signal.h> + +#include "../../gui/SignalIDs.h" +#include "Command.h" +#include "ProcessList.h" +#include "ccont.h" +#include "ksysguardd.h" + +CONTAINER ProcessList = 0; + +int fscale; + +#define BUFSIZE 1024 + +typedef struct +{ + /* This flag is set for all found processes at the beginning of the + * process list update. Processes that do not have this flag set will + * be assumed dead and removed from the list. The flag is cleared after + * each list update. */ + int alive; + + /* the process ID */ + pid_t pid; + + /* the parent process ID */ + pid_t ppid; + + /* the real user ID */ + uid_t uid; + + /* the real group ID */ + gid_t gid; + + /* a character description of the process status */ + char status[16]; + + /* the number of the tty the process owns */ + int ttyNo; + + /* + * The nice level. The range should be -20 to 20. I'm not sure + * whether this is true for all platforms. + */ + int niceLevel; + + /* + * The scheduling priority. + */ + int priority; + + /* + * The total amount of memory the process uses. This includes shared and + * swapped memory. + */ + unsigned int vmSize; + + /* + * The amount of physical memory the process currently uses. + */ + unsigned int vmRss; + + /* + * The amount of memory (shared/swapped/etc) the process shares with + * other processes. + */ + unsigned int vmLib; + + /* + * The number of 1/100 of a second the process has spend in user space. + * If a machine has an uptime of 1 1/2 years or longer this is not a + * good idea. I never thought that the stability of UNIX could get me + * into trouble! ;) + */ +#if !defined(__DragonFly__) + unsigned int userTime; +#else + long userTime; +#endif + + /* + * The number of 1/100 of a second the process has spend in system space. + * If a machine has an uptime of 1 1/2 years or longer this is not a + * good idea. I never thought that the stability of UNIX could get me + * into trouble! ;) + */ + unsigned int sysTime; + + /* system time as multime of 100ms */ + int centStamp; + + /* the current CPU load (in %) from user space */ + double userLoad; + + /* the current CPU load (in %) from system space */ + double sysLoad; + + /* the name of the process */ + char name[64]; + + /* the command used to start the process */ + char cmdline[256]; + + /* the login name of the user that owns this process */ + char userName[32]; +} ProcessInfo; + +static unsigned ProcessCount; + +static int +processCmp(void* p1, void* p2) +{ + return (((ProcessInfo*) p1)->pid - ((ProcessInfo*) p2)->pid); +} + +static ProcessInfo* +findProcessInList(int pid) +{ + ProcessInfo key; + long index; + + key.pid = pid; + if ((index = search_ctnr(ProcessList, processCmp, &key)) < 0) + return (0); + + return (get_ctnr(ProcessList, index)); +} + +static int +updateProcess(int pid) +{ + static char *statuses[] = { "idle","run","sleep","stop","zombie" }; + + ProcessInfo* ps; + struct passwd* pwent; + int mib[4]; + struct kinfo_proc p; + struct rusage pru; + size_t len; + size_t buflen = 256; + char buf[256]; + + if ((ps = findProcessInList(pid)) == 0) + { + ps = (ProcessInfo*) malloc(sizeof(ProcessInfo)); + ps->pid = pid; + ps->centStamp = 0; + push_ctnr(ProcessList, ps); + bsort_ctnr(ProcessList, processCmp); + } + + ps->alive = 1; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = pid; + + len = sizeof (p); + if (sysctl(mib, 4, &p, &len, NULL, 0) == -1 || !len) + return -1; + +#if __FreeBSD_version >= 500015 + ps->pid = p.ki_pid; + ps->ppid = p.ki_ppid; + ps->uid = p.ki_uid; + ps->gid = p.ki_pgid; + ps->priority = p.ki_pri.pri_user; + ps->niceLevel = p.ki_nice; +#elif defined(__DragonFly__) && __DragonFly_version >= 190000 + ps->pid = p.kp_pid; + ps->ppid = p.kp_ppid; + ps->uid = p.kp_uid; + ps->gid = p.kp_pgid; + ps->priority = p.kp_lwp.kl_tdprio; +#else + ps->pid = p.kp_proc.p_pid; + ps->ppid = p.kp_eproc.e_ppid; + ps->uid = p.kp_eproc.e_ucred.cr_uid; + ps->gid = p.kp_eproc.e_pgid; +#if defined(__DragonFly__) + ps->priority = p.kp_thread.td_pri; +#else + ps->priority = p.kp_proc.p_priority; +#endif + ps->niceLevel = p.kp_proc.p_nice; +#endif + + /* this isn't usertime -- it's total time (??) */ +#if __FreeBSD_version >= 500015 + ps->userTime = p.ki_runtime / 10000; +#elif defined(__DragonFly__) +#if __DragonFly_version >= 190000 + if (!getrusage(p.kp_pid, &pru)) +#else + if (!getrusage(p.kp_proc.p_pid, &pru)) +#endif + { + errx(1, "failed to get rusage info"); + } + ps->userTime = pru.ru_utime.tv_usec / 1000; /*p_runtime / 1000*/ +#elif __FreeBSD_version >= 300000 + ps->userTime = p.kp_proc.p_runtime / 10000; +#else + ps->userTime = p.kp_proc.p_rtime.tv_sec*100+p.kp_proc.p_rtime.tv_usec/100; +#endif + ps->sysTime = 0; + ps->sysLoad = 0; + + /* memory, process name, process uid */ + /* find out user name with process uid */ + pwent = getpwuid(ps->uid); + strncpy(ps->userName,pwent&&pwent->pw_name? pwent->pw_name:"????",sizeof(ps->userName)); + ps->userName[sizeof(ps->userName)-1]='\0'; + + if (fscale == 0) + ps->userLoad = 0; + else +#if __FreeBSD_version >= 500015 + ps->userLoad = 100.0 * (double) p.ki_pctcpu / fscale; + ps->vmSize = p.ki_size; + ps->vmRss = p.ki_rssize * getpagesize(); + strlcpy(ps->name,p.ki_comm? p.ki_comm:"????",sizeof(ps->name)); + strcpy(ps->status,(p.ki_stat>=1)&&(p.ki_stat<=5)? statuses[p.ki_stat-1]:"????"); +#elif defined (__DragonFly__) && __DragonFly_version >= 190000 + ps->userLoad = 100.0 * (double) p.kp_lwp.kl_pctcpu / fscale; + ps->vmSize = p.kp_vm_map_size; + ps->vmRss = p.kp_vm_rssize * getpagesize(); + strlcpy(ps->name,p.kp_comm ? p.kp_comm : "????", + sizeof(ps->name)); + strcpy(ps->status,(p.kp_stat>=1)&&(p.kp_stat<=5)? statuses[p.kp_stat-1]:"????"); +#else + ps->userLoad = 100.0 * (double) p.kp_proc.p_pctcpu / fscale; + ps->vmSize = p.kp_eproc.e_vm.vm_map.size; + ps->vmRss = p.kp_eproc.e_vm.vm_rssize * getpagesize(); +#if defined (__DragonFly__) + strlcpy(ps->name,p.kp_thread.td_comm ? p.kp_thread.td_comm : "????", + sizeof(ps->name)); +#else + strlcpy(ps->name,p.kp_proc.p_comm ? p.kp_proc.p_comm : "????", sizeof(ps->name)); + strcpy(ps->status,(p.kp_proc.p_stat>=1)&&(p.kp_proc.p_stat<=5)? statuses[p.kp_proc.p_stat-1]:"????"); +#endif +#endif + + /* process command line */ + /* do a sysctl to get the command line args. */ + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_ARGS; + mib[3] = pid; + + if ((sysctl(mib, 4, buf, &buflen, 0, 0) == -1) || !buflen) + strcpy(ps->cmdline, "????"); + else + strncpy(ps->cmdline, buf, buflen); + + return (0); +} + +static void +cleanupProcessList(void) +{ + ProcessInfo* ps; + + ProcessCount = 0; + /* All processes that do not have the active flag set are assumed dead + * and will be removed from the list. The alive flag is cleared. */ + for (ps = first_ctnr(ProcessList); ps; ps = next_ctnr(ProcessList)) + { + if (ps->alive) + { + /* Process is still alive. Just clear flag. */ + ps->alive = 0; + ProcessCount++; + } + else + { + /* Process has probably died. We remove it from the list and + * destruct the data structure. i needs to be decremented so + * that after i++ the next list element will be inspected. */ + free(remove_ctnr(ProcessList)); + } + } +} + +/* +================================ public part ================================== +*/ + +void +initProcessList(struct SensorModul* sm) +{ + size_t fscalelen; + ProcessList = new_ctnr(); + + registerMonitor("ps", "table", printProcessList, printProcessListInfo, sm); + registerMonitor("pscount", "integer", printProcessCount, printProcessCountInfo, sm); + + if (!RunAsDaemon) + { + registerCommand("kill", killProcess); + registerCommand("setpriority", setPriority); + } + + fscalelen = sizeof(fscale); + if (sysctlbyname("kern.fscale", &fscale, &fscalelen, NULL, 0) == -1) + fscale = 0; + + updateProcessList(); +} + +void +exitProcessList(void) +{ + removeMonitor("ps"); + removeMonitor("pscount"); + + if (ProcessList) + free (ProcessList); +} + +int +updateProcessList(void) +{ + 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 = malloc(len); + sysctl(mib, 3, p, &len, NULL, 0); + + for (num = 0; num < len / sizeof(struct kinfo_proc); num++) +#if __FreeBSD_version >= 500015 + updateProcess(p[num].ki_pid); +#elif __DragonFly_version >= 190000 + /* Skip kernel threads with pid -1. Swapper with pid 0 also + * causing problems is skipped in printProcessList() as 'kernel' + * entry. */ + if (p[num].kp_pid >= 0) + updateProcess(p[num].kp_pid); +#elif defined(__DragonFly__) + if (p[num].kp_proc.p_pid >= 0) + updateProcess(p[num].kp_proc.p_pid); +#else + updateProcess(p[num].kp_proc.p_pid); +#endif + free(p); + cleanupProcessList(); + + return (0); +} + +void +printProcessListInfo(const char* cmd) +{ + fprintf(CurrentClient, "Name\tPID\tPPID\tUID\tGID\tStatus\tUser%%\tSystem%%\tNice\tVmSize\tVmRss\tLogin\tCommand\n"); + fprintf(CurrentClient, "s\td\td\td\td\tS\tf\tf\td\tD\tD\ts\ts\n"); +} + +void +printProcessList(const char* cmd) +{ + ProcessInfo* ps; + + ps = first_ctnr(ProcessList); /* skip 'kernel' entry */ + for (ps = next_ctnr(ProcessList); ps; ps = next_ctnr(ProcessList)) + { + fprintf(CurrentClient, "%s\t%ld\t%ld\t%ld\t%ld\t%s\t%.2f\t%.2f\t%d\t%d\t%d\t%s\t%s\n", + ps->name, (long)ps->pid, (long)ps->ppid, + (long)ps->uid, (long)ps->gid, ps->status, + ps->userLoad, ps->sysLoad, ps->niceLevel, + ps->vmSize / 1024, ps->vmRss / 1024, ps->userName, ps->cmdline); + } +} + +void +printProcessCount(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", ProcessCount); +} + +void +printProcessCountInfo(const char* cmd) +{ + fprintf(CurrentClient, "Number of Processes\t1\t65535\t\n"); +} + +void +killProcess(const char* cmd) +{ + int sig, pid; + + sscanf(cmd, "%*s %d %d", &pid, &sig); + switch(sig) + { + case MENU_ID_SIGABRT: + sig = SIGABRT; + break; + case MENU_ID_SIGALRM: + sig = SIGALRM; + break; + case MENU_ID_SIGCHLD: + sig = SIGCHLD; + break; + case MENU_ID_SIGCONT: + sig = SIGCONT; + break; + case MENU_ID_SIGFPE: + sig = SIGFPE; + break; + case MENU_ID_SIGHUP: + sig = SIGHUP; + break; + case MENU_ID_SIGILL: + sig = SIGILL; + break; + case MENU_ID_SIGINT: + sig = SIGINT; + break; + case MENU_ID_SIGKILL: + sig = SIGKILL; + break; + case MENU_ID_SIGPIPE: + sig = SIGPIPE; + break; + case MENU_ID_SIGQUIT: + sig = SIGQUIT; + break; + case MENU_ID_SIGSEGV: + sig = SIGSEGV; + break; + case MENU_ID_SIGSTOP: + sig = SIGSTOP; + break; + case MENU_ID_SIGTERM: + sig = SIGTERM; + break; + case MENU_ID_SIGTSTP: + sig = SIGTSTP; + break; + case MENU_ID_SIGTTIN: + sig = SIGTTIN; + break; + case MENU_ID_SIGTTOU: + sig = SIGTTOU; + break; + case MENU_ID_SIGUSR1: + sig = SIGUSR1; + break; + case MENU_ID_SIGUSR2: + sig = SIGUSR2; + break; + } + if (kill((pid_t) pid, sig)) + { + switch(errno) + { + case EINVAL: + fprintf(CurrentClient, "4\t%d\n", pid); + break; + case ESRCH: + fprintf(CurrentClient, "3\t%d\n", pid); + break; + case EPERM: + fprintf(CurrentClient, "2\t%d\n", pid); + break; + default: + fprintf(CurrentClient, "1\t%d\n", pid); /* unknown error */ + break; + } + + } + else + fprintf(CurrentClient, "0\t%d\n", pid); +} + +void +setPriority(const char* cmd) +{ + int pid, prio; + + sscanf(cmd, "%*s %d %d", &pid, &prio); + if (setpriority(PRIO_PROCESS, pid, prio)) + { + switch(errno) + { + case EINVAL: + fprintf(CurrentClient, "4\n"); + break; + case ESRCH: + fprintf(CurrentClient, "3\n"); + break; + case EPERM: + case EACCES: + fprintf(CurrentClient, "2\n"); + break; + default: + fprintf(CurrentClient, "1\n"); /* unknown error */ + break; + } + } + else + fprintf(CurrentClient, "0\n"); +} diff --git a/ksysguard/ksysguardd/FreeBSD/ProcessList.h b/ksysguard/ksysguardd/FreeBSD/ProcessList.h new file mode 100644 index 000000000..925c55f5a --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/ProcessList.h @@ -0,0 +1,38 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@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 _process_list_h_ +#define _process_list_h_ + +void initProcessList(struct SensorModul* sm); +void exitProcessList(void); + +int updateProcessList(void); + +void printProcessList(const char*); +void printProcessListInfo(const char*); +void printProcessCount(const char* cmd); +void printProcessCountInfo(const char* cmd); + +void killProcess(const char* cmd); +void setPriority(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/FreeBSD/apm.c b/ksysguard/ksysguardd/FreeBSD/apm.c new file mode 100644 index 000000000..95efec792 --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/apm.c @@ -0,0 +1,102 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + +*/ + +#ifdef __i386__ + +#include <unistd.h> +#include <fcntl.h> +#include <machine/apm_bios.h> +#include <stdio.h> + +#include "Command.h" +#include "apm.h" +#include "ksysguardd.h" + +static int ApmFD, BattFill, BattTime; + +#define APMDEV "/dev/apm" + +/* +================================ public part ================================= +*/ + +void +initApm(struct SensorModul* sm) +{ + if ((ApmFD = open(APMDEV, O_RDONLY)) < 0) + return; + + if (updateApm() < 0) + return; + + registerMonitor("apm/batterycharge", "integer", printApmBatFill, + printApmBatFillInfo, sm); + registerMonitor("apm/remainingtime", "integer", printApmBatTime, + printApmBatTimeInfo, sm); +} + +void +exitApm(void) +{ + removeMonitor("apm/batterycharge"); + removeMonitor("apm/remainingtime"); + + close(ApmFD); +} + +int +updateApm(void) +{ + struct apm_info info; + int retval; + + retval = ioctl(ApmFD, APMIO_GETINFO, &info); + + BattFill = info.ai_batt_life; + BattTime = info.ai_batt_time; + + return retval; +} + +void +printApmBatFill(const char* c) +{ + fprintf(CurrentClient, "%d\n", BattFill); +} + +void +printApmBatFillInfo(const char* c) +{ + fprintf(CurrentClient, "Battery charge\t0\t100\t%%\n"); +} + +void +printApmBatTime(const char* c) +{ + fprintf(CurrentClient, "%d\n", BattTime); +} + +void +printApmBatTimeInfo(const char* c) +{ + fprintf(CurrentClient, "Remaining battery time\t0\t0\tmin\n"); +} + +#endif diff --git a/ksysguard/ksysguardd/FreeBSD/apm.h b/ksysguard/ksysguardd/FreeBSD/apm.h new file mode 100644 index 000000000..4e3c0c0d3 --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/apm.h @@ -0,0 +1,34 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 _apm_h_ +#define _apm_h_ + +void initApm(struct SensorModul* sm); +void exitApm(void); + +int updateApm(void); + +void printApmBatFill(const char*); +void printApmBatFillInfo(const char*); +void printApmBatTime(const char*); +void printApmBatTimeInfo(const char*); + +#endif diff --git a/ksysguard/ksysguardd/FreeBSD/diskstat.c b/ksysguard/ksysguardd/FreeBSD/diskstat.c new file mode 100644 index 000000000..04f64a706 --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/diskstat.c @@ -0,0 +1,256 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/ucred.h> +#include <sys/mount.h> +#include <time.h> +#include <unistd.h> + +#include "Command.h" +#include "ccont.h" +#include "diskstat.h" +#include "ksysguardd.h" + +typedef struct { + char device[256]; + char mntpnt[256]; + long blocks; + long bfree; + long bused; + int bused_percent; +} DiskInfo; + +static CONTAINER DiskStatList = 0; +static struct SensorModul* DiskStatSM; + +char *getMntPnt(const char *cmd) +{ + static char device[1025]; + char *ptr; + + memset(device, 0, sizeof(device)); + sscanf(cmd, "partitions%1024s", device); + + ptr = (char *)rindex(device, '/'); + *ptr = '\0'; + + return (char *)device; +} + +int numMntPnt(void) +{ + struct statfs *fs_info; + int i, n, counter = 0; + + n = getmntinfo(&fs_info, MNT_WAIT); + for (i = 0; i < n; i++) + if (strcmp(fs_info[i].f_fstypename, "procfs") && strcmp(fs_info[i].f_fstypename, "swap") && strcmp(fs_info[i].f_fstypename, "devfs")) + counter++; + + return counter; +} + +/* ------------------------------ public part --------------------------- */ + +void initDiskStat(struct SensorModul* sm) +{ + char monitor[1024]; + DiskInfo* disk_info; + + DiskStatList = new_ctnr(); + DiskStatSM = sm; + + updateDiskStat(); + + registerMonitor("partitions/list", "listview", printDiskStat, printDiskStatInfo, DiskStatSM); + + for (disk_info = first_ctnr(DiskStatList); disk_info; disk_info = next_ctnr(DiskStatList)) { + snprintf(monitor, sizeof(monitor), "partitions%s/usedspace", disk_info->mntpnt); + registerMonitor(monitor, "integer", printDiskStatUsed, printDiskStatUsedInfo, DiskStatSM); + snprintf(monitor, sizeof(monitor), "partitions%s/freespace", disk_info->mntpnt); + registerMonitor(monitor, "integer", printDiskStatFree, printDiskStatFreeInfo, DiskStatSM); + snprintf(monitor, sizeof(monitor), "partitions%s/filllevel", disk_info->mntpnt); + registerMonitor(monitor, "integer", printDiskStatPercent, printDiskStatPercentInfo, DiskStatSM); + } +} + +void checkDiskStat(void) +{ + if (numMntPnt() != level_ctnr(DiskStatList)) { + /* a filesystem was mounted or unmounted + so we do a reset */ + exitDiskStat(); + initDiskStat(DiskStatSM); + } +} + +void exitDiskStat(void) +{ + DiskInfo *disk_info; + char monitor[1024]; + + removeMonitor("partitions/list"); + + for (disk_info = first_ctnr(DiskStatList); disk_info; disk_info = next_ctnr(DiskStatList)) { + snprintf(monitor, sizeof(monitor), "partitions%s/usedspace", disk_info->mntpnt); + removeMonitor(monitor); + snprintf(monitor, sizeof(monitor), "partitions%s/freespace", disk_info->mntpnt); + removeMonitor(monitor); + snprintf(monitor, sizeof(monitor), "partitions%s/filllevel", disk_info->mntpnt); + removeMonitor(monitor); + } + + destr_ctnr(DiskStatList, free); +} + +int updateDiskStat(void) +{ + struct statfs *fs_info; + struct statfs fs; + float percent; + int i, mntcount; + DiskInfo *disk_info; + + /* let's hope there is no difference between the DiskStatList and + the number of mounted filesystems */ + for (i = level_ctnr(DiskStatList); i >= 0; --i) + free(pop_ctnr(DiskStatList)); + + mntcount = getmntinfo(&fs_info, MNT_WAIT); + + for (i = 0; i < mntcount; i++) { + fs = fs_info[i]; + if (strcmp(fs.f_fstypename, "procfs") && strcmp(fs.f_fstypename, "devfs") && strcmp(fs.f_fstypename, "devfs")) { + + if ( fs.f_blocks != 0 ) + { + percent = (((float)fs.f_blocks - (float)fs.f_bfree)/(float)fs.f_blocks); + percent = percent * 100; + } + else + percent = 0; + + if ((disk_info = (DiskInfo *)malloc(sizeof(DiskInfo))) == NULL) { + continue; + } + memset(disk_info, 0, sizeof(DiskInfo)); + strlcpy(disk_info->device, fs.f_mntfromname, sizeof(disk_info->device)); + if (!strcmp(fs.f_mntonname, "/")) { + strncpy(disk_info->mntpnt, "/root", 6); + } else { + strlcpy(disk_info->mntpnt, fs.f_mntonname, sizeof(disk_info->mntpnt)); + } + disk_info->blocks = fs.f_blocks; + disk_info->bfree = fs.f_bfree; + disk_info->bused = (fs.f_blocks - fs.f_bfree); + disk_info->bused_percent = (int)percent; + + push_ctnr(DiskStatList, disk_info); + } + } + + return 0; +} + +void printDiskStat(const char* cmd) +{ + DiskInfo* disk_info; + + for (disk_info = first_ctnr(DiskStatList); disk_info; disk_info = next_ctnr(DiskStatList)) { + fprintf(CurrentClient, "%s\t%ld\t%ld\t%ld\t%d\t%s\n", + disk_info->device, + disk_info->blocks, + disk_info->bused, + disk_info->bfree, + disk_info->bused_percent, + disk_info->mntpnt); + } + + fprintf(CurrentClient, "\n"); +} + +void printDiskStatInfo(const char* cmd) +{ + fprintf(CurrentClient, "Device\tBlocks\tUsed\tAvailable\tUsed %%\tMountPoint\nM\tD\tD\tD\td\ts\n"); +} + +void printDiskStatUsed(const char* cmd) +{ + DiskInfo* disk_info; + char *mntpnt = (char *)getMntPnt(cmd); + + for (disk_info = first_ctnr(DiskStatList); disk_info; disk_info = next_ctnr(DiskStatList)) { + if (!strcmp(mntpnt, disk_info->mntpnt)) { + fprintf(CurrentClient, "%ld\n", disk_info->bused); + } + } + + fprintf(CurrentClient, "\n"); +} + +void printDiskStatUsedInfo(const char* cmd) +{ + fprintf(CurrentClient, "Used Blocks\t0\t-\tBlocks\n"); +} + +void printDiskStatFree(const char* cmd) +{ + DiskInfo* disk_info; + char *mntpnt = (char *)getMntPnt(cmd); + + for (disk_info = first_ctnr(DiskStatList); disk_info; disk_info = next_ctnr(DiskStatList)) { + if (!strcmp(mntpnt, disk_info->mntpnt)) { + fprintf(CurrentClient, "%ld\n", disk_info->bfree); + } + } + + fprintf(CurrentClient, "\n"); +} + +void printDiskStatFreeInfo(const char* cmd) +{ + fprintf(CurrentClient, "Free Blocks\t0\t-\tBlocks\n"); +} + +void printDiskStatPercent(const char* cmd) +{ + DiskInfo* disk_info; + char *mntpnt = (char *)getMntPnt(cmd); + + for (disk_info = first_ctnr(DiskStatList); disk_info; disk_info = next_ctnr(DiskStatList)) { + if (!strcmp(mntpnt, disk_info->mntpnt)) { + fprintf(CurrentClient, "%d\n", disk_info->bused_percent); + } + } + + fprintf(CurrentClient, "\n"); +} + +void printDiskStatPercentInfo(const char* cmd) +{ + fprintf(CurrentClient, "Used Blocks\t0\t100\t%%\n"); +} diff --git a/ksysguard/ksysguardd/FreeBSD/diskstat.h b/ksysguard/ksysguardd/FreeBSD/diskstat.h new file mode 100644 index 000000000..06f247837 --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/diskstat.h @@ -0,0 +1,40 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 _diskstat_h_ +#define _diskstat_h_ + +void initDiskStat(struct SensorModul* sm); +void exitDiskStat(void); + +int updateDiskStat(void); +void checkDiskStat(void); + +void printDiskStat(const char* cmd); +void printDiskStatInfo(const char* cmd); + +void printDiskStatUsed(const char* cmd); +void printDiskStatUsedInfo(const char* cmd); +void printDiskStatFree(const char* cmd); +void printDiskStatFreeInfo(const char* cmd); +void printDiskStatPercent(const char* cmd); +void printDiskStatPercentInfo(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/FreeBSD/loadavg.c b/ksysguard/ksysguardd/FreeBSD/loadavg.c new file mode 100644 index 000000000..53eb9fc4e --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/loadavg.c @@ -0,0 +1,96 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdio.h> +#include <stdlib.h> + +#include "Command.h" +#include "ksysguardd.h" +#include "loadavg.h" + +static double LoadAvg[3]; + +/* +================================ public part ================================= +*/ + +void +initLoadAvg(struct SensorModul* sm) +{ + if (updateLoadAvg() < 0) + return; + + registerMonitor("cpu/loadavg1", "float", printLoadAvg1, + printLoadAvg1Info, sm); + registerMonitor("cpu/loadavg5", "float", printLoadAvg5, + printLoadAvg5Info, sm); + registerMonitor("cpu/loadavg15", "float", printLoadAvg15, + printLoadAvg15Info, sm); +} + +void +exitLoadAvg(void) +{ + removeMonitor("cpu/loadavg1"); + removeMonitor("cpu/loadavg5"); + removeMonitor("cpu/loadavg15"); +} + +int +updateLoadAvg(void) +{ + return getloadavg(LoadAvg, 3); +} + +void +printLoadAvg1(const char* c) +{ + fprintf(CurrentClient, "%f\n", LoadAvg[0]); +} + +void +printLoadAvg1Info(const char* c) +{ + fprintf(CurrentClient, "Load average 1 min\t0\t0\t\n"); +} + +void +printLoadAvg5(const char* c) +{ + fprintf(CurrentClient, "%f\n", LoadAvg[1]); +} + +void +printLoadAvg5Info(const char* c) +{ + fprintf(CurrentClient, "Load average 5 min\t0\t0\t\n"); +} + +void +printLoadAvg15(const char* c) +{ + fprintf(CurrentClient, "%f\n", LoadAvg[2]); +} + +void +printLoadAvg15Info(const char* c) +{ + fprintf(CurrentClient, "Load average 15 min\t0\t0\t\n"); +} diff --git a/ksysguard/ksysguardd/FreeBSD/loadavg.h b/ksysguard/ksysguardd/FreeBSD/loadavg.h new file mode 100644 index 000000000..801e4ef8d --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/loadavg.h @@ -0,0 +1,36 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 _loadavg_h_ +#define _loadavg_h_ + +void initLoadAvg(struct SensorModul* sm); +void exitLoadAvg(void); + +int updateLoadAvg(void); + +void printLoadAvg1(const char*); +void printLoadAvg1Info(const char*); +void printLoadAvg5(const char*); +void printLoadAvg5Info(const char*); +void printLoadAvg15(const char*); +void printLoadAvg15Info(const char*); + +#endif diff --git a/ksysguard/ksysguardd/FreeBSD/logfile.c b/ksysguard/ksysguardd/FreeBSD/logfile.c new file mode 100644 index 000000000..3b07ad8ac --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/logfile.c @@ -0,0 +1,175 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "Command.h" +#include "ccont.h" +#include "conf.h" +#include "ksysguardd.h" +#include "logfile.h" + +static CONTAINER LogFiles = 0; +static unsigned long counter = 1; + +typedef struct { + char name[256]; + FILE* fh; + unsigned long id; +} LogFileEntry; + +extern CONTAINER LogFileList; + +/* +================================ public part ================================= +*/ + +void initLogFile(struct SensorModul* sm) +{ + char monitor[1024]; + ConfigLogFile *entry; + + registerCommand("logfile_register", registerLogFile); + registerCommand("logfile_unregister", unregisterLogFile); + registerCommand("logfile_registered", printRegistered); + + for (entry = first_ctnr(LogFileList); entry; entry = next_ctnr(LogFileList)) + { + FILE* fp; + + /* register the log file if we can actually read the file. */ + if ((fp = fopen(entry->path, "r")) != NULL) + { + fclose(fp); + snprintf(monitor, 1024, "logfiles/%s", entry->name); + registerMonitor(monitor, "logfile", printLogFile, + printLogFileInfo, sm); + } + } + + LogFiles = new_ctnr(); +} + +void exitLogFile(void) +{ + destr_ctnr(LogFiles, free); +} + +void printLogFile(const char* cmd) +{ + char line[1024]; + unsigned long id; + int i; + char ch; + LogFileEntry *entry; + + sscanf(cmd, "%*s %lu", &id); + + for (entry = first_ctnr(LogFiles); entry; entry = next_ctnr(LogFiles)) { + if (entry->id == id) { + while (fgets(line, sizeof(line), entry->fh) != NULL) { + fprintf(CurrentClient, "%s", line); + } + clearerr(entry->fh); + } + } + + fprintf(CurrentClient, "\n"); +} + +void printLogFileInfo(const char* cmd) +{ + fprintf(CurrentClient, "LogFile\n"); +} + +void registerLogFile(const char* cmd) +{ + char name[257]; + FILE* file; + LogFileEntry *entry; + ConfigLogFile *conf; + + memset(name, 0, sizeof(name)); + sscanf(cmd, "%*s %256s", name); + + for (conf = first_ctnr(LogFileList); conf; conf = next_ctnr(LogFileList)) { + if (!strcmp(conf->name, name)) { + if ((file = fopen(conf->path, "r")) == NULL) { + print_error("fopen()"); + fprintf(CurrentClient, "0\n"); + return; + } + + fseek(file, 0, SEEK_END); + + if ((entry = (LogFileEntry *)malloc(sizeof(LogFileEntry))) == NULL) { + print_error("malloc()"); + fprintf(CurrentClient, "0\n"); + return; + } + + entry->fh = file; + strlcpy(entry->name, conf->name, sizeof(entry->name)); + entry->id = counter; + + push_ctnr(LogFiles, entry); + + fprintf(CurrentClient, "%lu\n", counter); + counter++; + + return; + } + } + + fprintf(CurrentClient, "0\n"); +} + +void unregisterLogFile(const char* cmd) +{ + unsigned long id; + LogFileEntry *entry; + + sscanf(cmd, "%*s %lu", &id); + + for (entry = first_ctnr(LogFiles); entry; entry = next_ctnr(LogFiles)) { + if (entry->id == id) { + fclose(entry->fh); + free(remove_ctnr(LogFiles)); + fprintf(CurrentClient, "\n"); + return; + } + } + + fprintf(CurrentClient, "\n"); +} + +void printRegistered(const char* cmd) +{ + LogFileEntry *entry; + + for (entry = first_ctnr(LogFiles); entry; entry = next_ctnr(LogFiles)) + fprintf(CurrentClient, "%s:%lu\n", entry->name, entry->id); + + fprintf(CurrentClient, "\n"); +} diff --git a/ksysguard/ksysguardd/FreeBSD/logfile.h b/ksysguard/ksysguardd/FreeBSD/logfile.h new file mode 100644 index 000000000..45ade9013 --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/logfile.h @@ -0,0 +1,36 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 _logfile_h_ +#define _logfile_h_ + +void initLogFile(struct SensorModul* sm); +void exitLogFile(void); + +void printLogFile(const char* cmd); +void printLogFileInfo(const char* cmd); + +void registerLogFile(const char* cmd); +void unregisterLogFile(const char* cmd); + +/* debug command */ +void printRegistered(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/FreeBSD/netdev.c b/ksysguard/ksysguardd/FreeBSD/netdev.c new file mode 100644 index 000000000..cec8be590 --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/netdev.c @@ -0,0 +1,353 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <config.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <sys/time.h> + +#include <net/if.h> +#include <net/if_mib.h> + +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "Command.h" +#include "ksysguardd.h" +#include "netdev.h" + + +typedef struct { + char name[32]; + u_long recBytes; + u_long recPacks; + u_long recErrs; + u_long recDrop; + u_long recMulticast; + u_long sentBytes; + u_long sentPacks; + u_long sentErrs; + u_long sentMulticast; + u_long sentColls; +} NetDevInfo; + +#define MAXNETDEVS 64 +static NetDevInfo NetDevs[MAXNETDEVS]; +static NetDevInfo NetDevsOld[MAXNETDEVS]; +static int NetDevCnt = 0; +static struct SensorModul* NetDevSM; + +static float elapsed = 0.0; +static struct timeval old_tv; + +char **parseCommand(const char *cmd) +{ + char *tmp_cmd = strdup(cmd); + char *begin; + char **retval = malloc(sizeof(char *)*2); + + begin = rindex(tmp_cmd, '/'); + *begin = '\0'; + begin++; + retval[1] = strdup((const char *)begin); /* sensor */ + + begin = rindex(tmp_cmd, '/'); + *begin = '\0'; + begin = rindex(tmp_cmd, '/'); + begin++; + retval[0] = strdup((const char *)begin); /* interface */ + free(tmp_cmd); + + return retval; +} + +int numActivIfaces(void) +{ + int counter = 0; + int name[6]; + int num_iface, i; + size_t len; + struct ifmibdata ifmd; + + len = sizeof(num_iface); + sysctlbyname("net.link.generic.system.ifcount", &num_iface, &len, NULL, 0); + + for (i = 1; i < num_iface + 1; i++) { + name[0] = CTL_NET; + name[1] = PF_LINK; + name[2] = NETLINK_GENERIC; + name[3] = IFMIB_IFDATA; + name[4] = i; + name[5] = IFDATA_GENERAL; + + len = sizeof(ifmd); + sysctl(name, 6, &ifmd, &len, NULL, 0); + if (ifmd.ifmd_flags & IFF_UP) + counter++; + } + + return counter; +} + +/* ------------------------------ public part --------------------------- */ + +void initNetDev(struct SensorModul* sm) +{ + int i; + char monitor[1024]; + gettimeofday(&old_tv, (struct timezone *)0); + + NetDevSM = sm; + + updateNetDev(); + + for (i = 0; i < NetDevCnt; i++) { + /* init data */ + NetDevsOld[i] = NetDevs[i]; + + /* register monitors */ + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/receiver/data", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevRecBytes, printNetDevRecBytesInfo, NetDevSM); + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/receiver/packets", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevRecBytes, printNetDevRecBytesInfo, NetDevSM); + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/receiver/errors", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevRecBytes, printNetDevRecBytesInfo, NetDevSM); + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/receiver/drops", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevRecBytes, printNetDevRecBytesInfo, NetDevSM); + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/receiver/multicast", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevRecBytes, printNetDevRecBytesInfo, NetDevSM); + + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/transmitter/data", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevSentBytes, printNetDevSentBytesInfo, NetDevSM); + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/transmitter/packets", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevSentBytes, printNetDevSentBytesInfo, NetDevSM); + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/transmitter/errors", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevSentBytes, printNetDevSentBytesInfo, NetDevSM); + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/transmitter/multicast", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevSentBytes, printNetDevSentBytesInfo, NetDevSM); + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/transmitter/collisions", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevSentBytes, printNetDevSentBytesInfo, NetDevSM); + } +} + +void exitNetDev(void) +{ + int i; + char monitor[1024]; + + for (i = 0; i < NetDevCnt; i++) { + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/receiver/data", NetDevs[i].name); + removeMonitor(monitor); + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/receiver/packets", NetDevs[i].name); + removeMonitor(monitor); + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/receiver/errors", NetDevs[i].name); + removeMonitor(monitor); + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/receiver/drops", NetDevs[i].name); + removeMonitor(monitor); + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/receiver/multicast", NetDevs[i].name); + removeMonitor(monitor); + + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/transmitter/data", NetDevs[i].name); + removeMonitor(monitor); + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/transmitter/packets", NetDevs[i].name); + removeMonitor(monitor); + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/transmitter/errors", NetDevs[i].name); + removeMonitor(monitor); + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/transmitter/multicast", NetDevs[i].name); + removeMonitor(monitor); + snprintf(monitor, sizeof(monitor), "network/interfaces/%s/transmitter/collisions", NetDevs[i].name); + removeMonitor(monitor); + } +} + +int updateNetDev(void) +{ + int name[6]; + int num_iface, i; + size_t len; + struct ifmibdata ifmd; + struct timeval new_tv, tv; + + len = sizeof(num_iface); + sysctlbyname("net.link.generic.system.ifcount", &num_iface, &len, NULL, 0); + + NetDevCnt = 0; + for (i = 1; i < num_iface + 1; i++) { + name[0] = CTL_NET; + name[1] = PF_LINK; + name[2] = NETLINK_GENERIC; + name[3] = IFMIB_IFDATA; + name[4] = i; + name[5] = IFDATA_GENERAL; + + len = sizeof(ifmd); + sysctl(name, 6, &ifmd, &len, NULL, 0); + if (ifmd.ifmd_flags & IFF_UP) { + NetDevsOld[NetDevCnt] = NetDevs[NetDevCnt]; + + strlcpy(NetDevs[NetDevCnt].name, ifmd.ifmd_name, sizeof(NetDevs[NetDevCnt].name)); + NetDevs[NetDevCnt].recBytes = ifmd.ifmd_data.ifi_ibytes; + NetDevs[NetDevCnt].recPacks = ifmd.ifmd_data.ifi_ipackets; + NetDevs[NetDevCnt].recErrs = ifmd.ifmd_data.ifi_ierrors; + NetDevs[NetDevCnt].recDrop = ifmd.ifmd_data.ifi_iqdrops; + NetDevs[NetDevCnt].recMulticast = ifmd.ifmd_data.ifi_imcasts; + NetDevs[NetDevCnt].sentBytes = ifmd.ifmd_data.ifi_obytes; + NetDevs[NetDevCnt].sentPacks = ifmd.ifmd_data.ifi_opackets; + NetDevs[NetDevCnt].sentErrs = ifmd.ifmd_data.ifi_oerrors; + NetDevs[NetDevCnt].sentMulticast = ifmd.ifmd_data.ifi_omcasts; + NetDevs[NetDevCnt].sentColls = ifmd.ifmd_data.ifi_collisions; + NetDevCnt++; + } + } + + gettimeofday(&new_tv, (struct timezone *)0); + timersub(&new_tv, &old_tv, &tv); + elapsed = tv.tv_sec + (tv.tv_usec * 1e-6); + old_tv = new_tv; + + return 0; +} + +void checkNetDev(void) +{ + if (numActivIfaces() != NetDevCnt) { + /* interface has been added or removed + so we do a reset */ + exitNetDev(); + initNetDev(NetDevSM); + } +} + +void printNetDevRecBytes(const char *cmd) +{ + int i; + char **retval; + + retval = parseCommand(cmd); + + if (retval == NULL) + return; + + for (i = 0; i < NetDevCnt; i++) { + if (!strcmp(NetDevs[i].name, retval[0])) { + if (!strncmp(retval[1], "data", 4)) + fprintf(CurrentClient, "%lu", (u_long)((NetDevs[i].recBytes - NetDevsOld[i].recBytes) / (1024 * elapsed))); + if (!strncmp(retval[1], "packets", 7)) + fprintf(CurrentClient, "%lu", (u_long)((NetDevs[i].recPacks - NetDevsOld[i].recPacks) / elapsed)); + if (!strncmp(retval[1], "errors", 6)) + fprintf(CurrentClient, "%lu", (u_long)((NetDevs[i].recErrs - NetDevsOld[i].recErrs) / elapsed)); + if (!strncmp(retval[1], "drops", 5)) + fprintf(CurrentClient, "%lu", (u_long)((NetDevs[i].recDrop - NetDevsOld[i].recDrop) / elapsed)); + if (!strncmp(retval[1], "multicast", 9)) + fprintf(CurrentClient, "%lu", (u_long)((NetDevs[i].recMulticast - NetDevsOld[i].recMulticast) / elapsed)); + } + } + free(retval[0]); + free(retval[1]); + free(retval); + + fprintf(CurrentClient, "\n"); +} + +void printNetDevRecBytesInfo(const char *cmd) +{ + char **retval; + + retval = parseCommand(cmd); + + if (retval == NULL) + return; + + if (!strncmp(retval[1], "data", 4)) + fprintf(CurrentClient, "Received Data\t0\t0\tkBytes/s\n"); + if (!strncmp(retval[1], "packets", 7)) + fprintf(CurrentClient, "Received Packets\t0\t0\t1/s\n"); + if (!strncmp(retval[1], "errors", 6)) + fprintf(CurrentClient, "Receiver Errors\t0\t0\t1/s\n"); + if (!strncmp(retval[1], "drops", 5)) + fprintf(CurrentClient, "Receiver Drops\t0\t0\t1/s\n"); + if (!strncmp(retval[1], "multicast", 9)) + fprintf(CurrentClient, "Received Multicast Packets\t0\t0\t1/s\n"); + + free(retval[0]); + free(retval[1]); + free(retval); +} + +void printNetDevSentBytes(const char *cmd) +{ + int i; + char **retval; + + retval = parseCommand(cmd); + + if (retval == NULL) + return; + + for (i = 0; i < NetDevCnt; i++) { + if (!strcmp(NetDevs[i].name, retval[0])) { + if (!strncmp(retval[1], "data", 4)) + fprintf(CurrentClient, "%lu", (u_long)((NetDevs[i].sentBytes - NetDevsOld[i].sentBytes) / (1024 * elapsed))); + if (!strncmp(retval[1], "packets", 7)) + fprintf(CurrentClient, "%lu", (u_long)((NetDevs[i].sentPacks - NetDevsOld[i].sentPacks) / elapsed)); + if (!strncmp(retval[1], "errors", 6)) + fprintf(CurrentClient, "%lu", (u_long)((NetDevs[i].sentErrs - NetDevsOld[i].sentErrs) / elapsed)); + if (!strncmp(retval[1], "multicast", 9)) + fprintf(CurrentClient, "%lu", (u_long)((NetDevs[i].sentMulticast - NetDevsOld[i].sentMulticast) / elapsed)); + if (!strncmp(retval[1], "collisions", 10)) + fprintf(CurrentClient, "%lu", (u_long)((NetDevs[i].sentColls - NetDevsOld[i].sentColls) / elapsed)); + } + } + free(retval[0]); + free(retval[1]); + free(retval); + + fprintf(CurrentClient, "\n"); +} + +void printNetDevSentBytesInfo(const char *cmd) +{ + char **retval; + + retval = parseCommand(cmd); + + if (retval == NULL) + return; + + if (!strncmp(retval[1], "data", 4)) + fprintf(CurrentClient, "Sent Data\t0\t0\tkBytes/s\n"); + if (!strncmp(retval[1], "packets", 7)) + fprintf(CurrentClient, "Sent Packets\t0\t0\t1/s\n"); + if (!strncmp(retval[1], "errors", 6)) + fprintf(CurrentClient, "Transmitter Errors\t0\t0\t1/s\n"); + if (!strncmp(retval[1], "multicast", 9)) + fprintf(CurrentClient, "Sent Multicast Packets\t0\t0\t1/s\n"); + if (!strncmp(retval[1], "collisions", 10)) + fprintf(CurrentClient, "Transmitter Collisions\t0\t0\t1/s\n"); + + free(retval[0]); + free(retval[1]); + free(retval); +} diff --git a/ksysguard/ksysguardd/FreeBSD/netdev.h b/ksysguard/ksysguardd/FreeBSD/netdev.h new file mode 100644 index 000000000..17d9c89e9 --- /dev/null +++ b/ksysguard/ksysguardd/FreeBSD/netdev.h @@ -0,0 +1,35 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 _netdev_h_ +#define _netdev_h_ + +void initNetDev(struct SensorModul* sm); +void exitNetDev(void); + +int updateNetDev(void); +void checkNetDev(void); + +void printNetDevRecBytes(const char* cmd); +void printNetDevRecBytesInfo(const char* cmd); +void printNetDevSentBytes(const char* cmd); +void printNetDevSentBytesInfo(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/Irix/LoadAvg.c b/ksysguard/ksysguardd/Irix/LoadAvg.c new file mode 100644 index 000000000..92d284756 --- /dev/null +++ b/ksysguard/ksysguardd/Irix/LoadAvg.c @@ -0,0 +1,78 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + Irix support by Carsten Kroll <CKroll@pinnaclesys.com> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/swap.h> + +#include "config.h" + +#include "ksysguardd.h" +#include "Command.h" +#include "LoadAvg.h" + +double loadavg1 = 0.0; +double loadavg5 = 0.0; +double loadavg15 = 0.0; + +void initLoadAvg(struct SensorModul* sm ) { + registerMonitor( "cpu/loadavg1", "float", + printLoadAvg1, printLoadAvg1Info, sm ); + registerMonitor( "cpu/loadavg5", "float", + printLoadAvg5, printLoadAvg5Info, sm ); + registerMonitor( "cpu/loadavg15", "float", + printLoadAvg15, printLoadAvg15Info, sm ); +} + +void exitLoadAvg( void ) { +} + +int updateLoadAvg( void ) { + + return( 0 ); +} + +void printLoadAvg1Info( const char *cmd ) { + fprintf(CurrentClient, "avnrun 1min\t0\t0\n" ); +} + +void printLoadAvg1( const char *cmd ) { + fprintf(CurrentClient, "%f\n", loadavg1 ); +} + +void printLoadAvg5Info( const char *cmd ) { + fprintf(CurrentClient, "avnrun 5min\t0\t0\n" ); +} + +void printLoadAvg5( const char *cmd ) { + fprintf(CurrentClient, "%f\n", loadavg5 ); +} + +void printLoadAvg15Info( const char *cmd ) { + fprintf(CurrentClient, "avnrun 15min\t0\t0\n" ); +} + +void printLoadAvg15( const char *cmd ) { + fprintf(CurrentClient, "%f\n", loadavg15 ); +} diff --git a/ksysguard/ksysguardd/Irix/LoadAvg.h b/ksysguard/ksysguardd/Irix/LoadAvg.h new file mode 100644 index 000000000..eea8ad82e --- /dev/null +++ b/ksysguard/ksysguardd/Irix/LoadAvg.h @@ -0,0 +1,41 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@kde.org> + + Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + + 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 _LoadAvg_h_ +#define _LoadAvg_h_ + +#define LOAD(a) ((double)(a) / (1 << 8 )) + +void initLoadAvg(struct SensorModul* sm); +void exitLoadAvg(void); + +int updateLoadAvg(void); + +void printLoadAvg1( const char *cmd ); +void printLoadAvg1Info( const char *cmd ); +void printLoadAvg5( const char *cmd ); +void printLoadAvg5Info( const char *cmd ); +void printLoadAvg15( const char *cmd ); +void printLoadAvg15Info( const char *cmd ); + +#endif /* _LoadAvg_h_ */ diff --git a/ksysguard/ksysguardd/Irix/Makefile.am b/ksysguard/ksysguardd/Irix/Makefile.am new file mode 100644 index 000000000..3c1997924 --- /dev/null +++ b/ksysguard/ksysguardd/Irix/Makefile.am @@ -0,0 +1,4 @@ +INCLUDES = -I$(srcdir)/../../CContLib -I.. + +noinst_LIBRARIES = libksysguardd.a +libksysguardd_a_SOURCES = Memory.c LoadAvg.c ProcessList.c NetDev.c cpu.c diff --git a/ksysguard/ksysguardd/Irix/Memory.c b/ksysguard/ksysguardd/Irix/Memory.c new file mode 100644 index 000000000..e88123ddd --- /dev/null +++ b/ksysguard/ksysguardd/Irix/Memory.c @@ -0,0 +1,128 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + Irix support by Carsten Kroll <ckroll@pinnaclesys.com> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/statfs.h> +#include <sys/swap.h> +#include <sys/sysmp.h> + +#include "config.h" + +#include "ksysguardd.h" +#include "Command.h" +#include "Memory.h" + +static int Dirty = 1; +static t_memsize totalmem = (t_memsize) 0; +static t_memsize freemem = (t_memsize) 0; +static unsigned long totalswap = 0L,vswap = 0L; +static unsigned long freeswap = 0L,bufmem = 0L ; + +void initMemory( struct SensorModul* sm ) { + + registerMonitor( "mem/physical/free", "integer", + printMemFree, printMemFreeInfo, sm ); + registerMonitor( "mem/physical/used", "integer", + printMemUsed, printMemUsedInfo, sm ); + registerMonitor( "mem/swap/free", "integer", + printSwapFree, printSwapFreeInfo, sm ); + registerMonitor( "mem/swap/used", "integer", + printSwapUsed, printSwapUsedInfo, sm ); +} + +void exitMemory( void ) { +} + +int updateMemory( void ) { + struct statfs sf; + off_t val; + int pagesize = getpagesize(); + struct rminfo rmi; + if( sysmp(MP_SAGET, MPSA_RMINFO, &rmi, sizeof(rmi)) == -1 ) + return( -1 ); + totalmem = rmi.physmem*pagesize/1024; // total physical memory (without swaps) + freemem = rmi.freemem*pagesize/1024; // total free physical memory (without swaps) + bufmem = rmi.bufmem *pagesize/1024; + + statfs ("/proc", &sf,sizeof(sf),0); + + swapctl(SC_GETSWAPVIRT,&val); + vswap = val >> 1; + swapctl(SC_GETSWAPTOT,&val); + totalswap = val >> 1; + swapctl(SC_GETFREESWAP,&val); + freeswap = val >> 1; + + Dirty = 1; + + return( 0 ); +} + +void printMemFreeInfo( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "Free Memory\t0\t%ld\tKB\n", freemem ); +} + +void printMemFree( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "%ld\n", freemem ); +} + +void printMemUsedInfo( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "Used Memory\t0\t%ld\tKB\n", totalmem - freemem ); +} + +void printMemUsed( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "%ld\n", totalmem - freemem ); +} + +void printSwapFreeInfo( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "Free Swap\t0\t%ld\tKB\n", freeswap ); +} + +void printSwapFree( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "%ld\n", freeswap ); +} +void printSwapUsedInfo( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "Used Swap\t0\t%ld\tKB\n", totalswap - freeswap ); +} + +void printSwapUsed( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "%ld\n", totalswap - freeswap ); +} diff --git a/ksysguard/ksysguardd/Irix/Memory.h b/ksysguard/ksysguardd/Irix/Memory.h new file mode 100644 index 000000000..ac3677b13 --- /dev/null +++ b/ksysguard/ksysguardd/Irix/Memory.h @@ -0,0 +1,46 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@kde.org> + + Irix support by Carsten Kroll <ckroll@pinnaclesys.com> + + 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 _Memory_h_ +#define _Memory_h_ + +typedef unsigned long t_memsize; + +void initMemory(struct SensorModul* sm); +void exitMemory(void); + +int updateMemory(void); + +void printMemFree( const char *cmd ); +void printMemFreeInfo( const char *cmd ); +void printMemUsed( const char *cmd ); +void printMemUsedInfo( const char *cmd ); +void printMemBuff( const char *cmd); +void printMemBuffInfo( const char *cmd); + +void printSwapFree( const char *cmd ); +void printSwapFreeInfo( const char *cmd ); +void printSwapUsed( const char *cmd ); +void printSwapUsedInfo( const char *cmd ); + +#endif /* _Memory_h */ diff --git a/ksysguard/ksysguardd/Irix/NetDev.c b/ksysguard/ksysguardd/Irix/NetDev.c new file mode 100644 index 000000000..80bc2b310 --- /dev/null +++ b/ksysguard/ksysguardd/Irix/NetDev.c @@ -0,0 +1,343 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + Irix Support by Carsten Kroll <ckroll@pinnaclesys.com> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <fcntl.h> +#include <sys/socket.h> +#include <net/if.h> +#include <net/soioctl.h> +#include <stdio.h> +#include <string.h> +#include <sys/sysctl.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <invent.h> +#include <strings.h> + + +#include "Command.h" +#include "ksysguardd.h" +#include "NetDev.h" + +#ifdef __GNUC__ +#define LONGLONG long long +#endif + +typedef struct { + char name[IFNAMSIZ]; + u_long recBytes; + u_long recPacks; + u_long recErrs; + u_long recDrop; + u_long recMulticast; + u_long sentBytes; + u_long sentPacks; + u_long sentErrs; + u_long sentMulticast; + u_long sentColls; +} NetDevInfo; + +#define MAXNETDEVS 32 +static NetDevInfo NetDevs[MAXNETDEVS]; +static NetDevInfo oNetDevs[MAXNETDEVS]; +static int NetDevCnt = 0; + +char **parseCommand(const char *cmd) +{ + char *tmp_cmd = strdup(cmd); + char *begin; + char *retval = malloc(sizeof(char *)*2); + + begin = rindex(tmp_cmd, '/'); + *begin = '\0'; + begin++; + retval[1] = strdup(begin); // sensor + + begin = rindex(tmp_cmd, '/'); + *begin = '\0'; + begin = rindex(tmp_cmd, '/'); + begin++; + retval[0] = strdup(begin); // interface + free(tmp_cmd); + + return retval; +} + +/* ------------------------------ public part --------------------------- */ + +void initNetDev(struct SensorModul* sm) +{ + int i; + char monitor[1024]; + + memset(NetDevs,0,sizeof(NetDevInfo)*MAXNETDEVS); + memset(oNetDevs,0,sizeof(NetDevInfo)*MAXNETDEVS); + + updateNetDev(); + + for (i = 0; i < NetDevCnt; i++) { + + sprintf(monitor,"network/interfaces/%s/receiver/packets", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevRecBytes, printNetDevRecBytesInfo, sm); + sprintf(monitor ,"network/interfaces/%s/receiver/errors", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevRecBytes, printNetDevRecBytesInfo, sm); + /* + [CK] I don't know how to get Bytes sent/received, if someone does please drop me a note. + sprintf(monitor,"network/interfaces/%s/receiver/data", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevRecBytes, printNetDevRecBytesInfo, sm); + sprintf(monitor,"network/interfaces/%s/receiver/drops", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevRecBytes, printNetDevRecBytesInfo, sm); + sprintf(monitor ,"network/interfaces/%s/receiver/multicast", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevRecBytes, printNetDevRecBytesInfo, sm); + */ + + sprintf(monitor,"network/interfaces/%s/transmitter/packets", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevSentBytes, printNetDevSentBytesInfo, sm); + sprintf(monitor,"network/interfaces/%s/transmitter/errors", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevSentBytes, printNetDevSentBytesInfo, sm); + /* + sprintf(monitor,"network/interfaces/%s/transmitter/data", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevSentBytes, printNetDevSentBytesInfo, sm); + sprintf(monitor,"network/interfaces/%s/transmitter/multicast", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevSentBytes, printNetDevSentBytesInfo, sm); + */ + sprintf(monitor,"network/interfaces/%s/transmitter/collisions", NetDevs[i].name); + registerMonitor(monitor, "integer", printNetDevSentBytes, printNetDevSentBytesInfo, sm); + } +} + +void exitNetDev(void) +{ + int i; + char monitor[1024]; + + for (i = 0; i < NetDevCnt; i++) { + sprintf(monitor,"network/interfaces/%s/receiver/packets", NetDevs[i].name); + removeMonitor(monitor); + sprintf(monitor,"network/interfaces/%s/receiver/errors", NetDevs[i].name); + removeMonitor(monitor); +/* + sprintf(monitor,"network/interfaces/%s/receiver/drops", NetDevs[i].name); + removeMonitor(monitor); + sprintf(monitor,"network/interfaces/%s/receiver/multicast", NetDevs[i].name); + removeMonitor(monitor); + sprintf(monitor,"network/interfaces/%s/receiver/data", NetDevs[i].name); + removeMonitor(monitor); +*/ + + sprintf(monitor,"network/interfaces/%s/transmitter/packets", NetDevs[i].name); + removeMonitor(monitor); + sprintf(monitor,"network/interfaces/%s/transmitter/errors", NetDevs[i].name); + removeMonitor(monitor); +/* + sprintf(monitor,"network/interfaces/%s/transmitter/data", NetDevs[i].name); + removeMonitor(monitor); + sprintf(monitor,"network/interfaces/%s/transmitter/multicast", NetDevs[i].name); + removeMonitor(monitor); +*/ + sprintf(monitor,"network/interfaces/%s/transmitter/collisions", NetDevs[i].name); + removeMonitor(monitor); + + } +} + +int updateNetDev(void) +{ + int name[6]; + int num_iface=0, i; + char buf[MAXNETDEVS*sizeof(struct ifreq)]; + size_t len; + int s; + struct ifconf ifc; + struct ifstats *istat; + struct timeval tv; + static LONGLONG timestamp=0; + register LONGLONG cts,elapsed; + //struct ipstat ips; + + if ((s=socket(PF_INET,SOCK_DGRAM,0)) < 0){ + print_error("socket creation failed"); + return(-1); + } + + ifc.ifc_len = sizeof (buf); + ifc.ifc_buf = buf; + if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { + print_error("cannot get interface configuration"); + return(-1); + } + + gettimeofday(&tv, 0); + cts = ((LONGLONG)tv.tv_sec * 100 + (LONGLONG) tv.tv_usec / 10000);/* in 10 ms unit*/ + elapsed = cts - timestamp; + timestamp=cts; + + NetDevCnt=0; + + for (i = 0; i < MAXNETDEVS; i++) { + if ( *ifc.ifc_req[i].ifr_name == 0) break; + if (ioctl(s, SIOCGIFSTATS, &ifc.ifc_req[i]) < 0) { + print_error("cannot get interface statistics"); + return (-1); + } + istat=&ifc.ifc_req[i].ifr_stats; + //if ( ifc.ifc_req[i].ifr_flags & IFF_UP) { + strncpy(NetDevs[i].name,ifc.ifc_req[i].ifr_name, IFNAMSIZ); + NetDevs[i].name[IFNAMSIZ-1]='\0'; + NetDevs[i].recBytes = (istat->ifs_ipackets - oNetDevs[i].recBytes) * 100 / elapsed; + NetDevs[i].recPacks = (istat->ifs_ipackets - oNetDevs[i].recPacks) * 100 / elapsed; + NetDevs[i].recErrs = istat->ifs_ierrors - oNetDevs[i].recErrs; + //NetDevs[i].recDrop = istat - oNetDevs[i].recDrop; + //NetDevs[i].recMulticast = istat - oNetDevs[i].recMulticast; + NetDevs[i].sentBytes = istat->ifs_opackets - oNetDevs[i].sentBytes; + NetDevs[i].sentPacks = (istat->ifs_opackets - oNetDevs[i].sentPacks) * 100 / elapsed; + NetDevs[i].sentErrs = (istat->ifs_oerrors - oNetDevs[i].sentErrs) * 100 / elapsed; + //NetDevs[i].sentMulticast = istat - NetDevs[i].sentMulticast; + NetDevs[i].sentColls = (istat->ifs_collisions - oNetDevs[i].sentColls) *100/elapsed; + /* save it for the next round */ + oNetDevs[i].recBytes = istat->ifs_ipackets; + oNetDevs[i].recPacks = istat->ifs_ipackets; + oNetDevs[i].recErrs = istat->ifs_ierrors; + //oNetDevs[i].recDrop = + //oNetDevs[i].recMulticast = + oNetDevs[i].sentBytes = istat->ifs_opackets; + oNetDevs[i].sentPacks = istat->ifs_opackets; + oNetDevs[i].sentErrs = istat->ifs_oerrors; + //oNetDevs[i].sentMulticast = + oNetDevs[i].sentColls = istat->ifs_collisions; + //} + NetDevCnt++; + } + close(s); + return (0); +} + +void printNetDevRecBytes(const char *cmd) +{ + int i; + char **retval; + + retval = parseCommand(cmd); + + if (retval == NULL) + return; + + for (i = 0; i < NetDevCnt; i++) { + if (!strcmp(NetDevs[i].name, retval[0])) { + if (!strncmp(retval[1], "data", 4)) + fprintf(CurrentClient, "%lu", NetDevs[i].recBytes); + if (!strncmp(retval[1], "packets", 7)) + fprintf(CurrentClient, "%lu", NetDevs[i].recPacks); + if (!strncmp(retval[1], "errors", 6)) + fprintf(CurrentClient, "%lu", NetDevs[i].recErrs); + if (!strncmp(retval[1], "drops", 5)) + fprintf(CurrentClient, "%lu", NetDevs[i].recDrop); + if (!strncmp(retval[1], "multicast", 9)) + fprintf(CurrentClient, "%lu", NetDevs[i].recMulticast); + } + } + free(retval[0]); + free(retval[1]); + free(retval); + + fprintf(CurrentClient, "\n"); +} + +void printNetDevRecBytesInfo(const char *cmd) +{ + char **retval; + + retval = parseCommand(cmd); + + if (retval == NULL) + return; + + if (!strncmp(retval[1], "data", 4)) + fprintf(CurrentClient, "Received Data\t0\t0\tkBytes/s\n"); + if (!strncmp(retval[1], "packets", 7)) + fprintf(CurrentClient, "Received Packets\t0\t0\t1/s\n"); + if (!strncmp(retval[1], "errors", 6)) + fprintf(CurrentClient, "Receiver Errors\t0\t0\t1/s\n"); + if (!strncmp(retval[1], "drops", 5)) + fprintf(CurrentClient, "Receiver Drops\t0\t0\t1/s\n"); + if (!strncmp(retval[1], "multicast", 9)) + fprintf(CurrentClient, "Received Multicast Packets\t0\t0\t1/s\n"); + + free(retval[0]); + free(retval[1]); + free(retval); +} + +void printNetDevSentBytes(const char *cmd) +{ + int i; + char **retval; + + retval = parseCommand(cmd); + + if (retval == NULL) + return; + + for (i = 0; i < NetDevCnt; i++) { + if (!strcmp(NetDevs[i].name, retval[0])) { + if (!strncmp(retval[1], "data", 4)) + fprintf(CurrentClient, "%lu", NetDevs[i].sentBytes); + if (!strncmp(retval[1], "packets", 7)) + fprintf(CurrentClient, "%lu", NetDevs[i].sentPacks); + if (!strncmp(retval[1], "errors", 6)) + fprintf(CurrentClient, "%lu", NetDevs[i].sentErrs); + if (!strncmp(retval[1], "multicast", 9)) + fprintf(CurrentClient, "%lu", NetDevs[i].sentMulticast); + if (!strncmp(retval[1], "collisions", 10)) + fprintf(CurrentClient, "%lu", NetDevs[i].sentColls); + } + } + free(retval[0]); + free(retval[1]); + free(retval); + + fprintf(CurrentClient, "\n"); +} + +void printNetDevSentBytesInfo(const char *cmd) +{ + char **retval; + + retval = parseCommand(cmd); + + if (retval == NULL) + return; + + if (!strncmp(retval[1], "data", 4)) + fprintf(CurrentClient, "Sent Data\t0\t0\tkBytes/s\n"); + if (!strncmp(retval[1], "packets", 7)) + fprintf(CurrentClient, "Sent Packets\t0\t0\t1/s\n"); + if (!strncmp(retval[1], "errors", 6)) + fprintf(CurrentClient, "Transmitter Errors\t0\t0\t1/s\n"); + if (!strncmp(retval[1], "multicast", 9)) + fprintf(CurrentClient, "Sent Multicast Packets\t0\t0\t1/s\n"); + if (!strncmp(retval[1], "collisions", 10)) + fprintf(CurrentClient, "Transmitter Collisions\t0\t0\t1/s\n"); + + free(retval[0]); + free(retval[1]); + free(retval); +} diff --git a/ksysguard/ksysguardd/Irix/NetDev.h b/ksysguard/ksysguardd/Irix/NetDev.h new file mode 100644 index 000000000..aa30166e9 --- /dev/null +++ b/ksysguard/ksysguardd/Irix/NetDev.h @@ -0,0 +1,35 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + Irix support by Carsten Kroll <ckroll@pinnaclesys.com> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 _netdev_h_ +#define _netdev_h_ + +void initNetDev(struct SensorModul* sm); +void exitNetDev(void); + +int updateNetDev(void); + +void printNetDevRecBytes(const char* cmd); +void printNetDevRecBytesInfo(const char* cmd); +void printNetDevSentBytes(const char* cmd); +void printNetDevSentBytesInfo(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/Irix/ProcessList.c b/ksysguard/ksysguardd/Irix/ProcessList.c new file mode 100644 index 000000000..523d87d26 --- /dev/null +++ b/ksysguard/ksysguardd/Irix/ProcessList.c @@ -0,0 +1,462 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + Irix support by Carsten Kroll <ckroll@pinnaclesys.com> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/types.h> +#include <dirent.h> +#include <pwd.h> +#include <sys/resource.h> +#include <sys/procfs.h> +#include <sys/statfs.h> +#include <sys/sysmp.h> +#include <sys/sysinfo.h> + +#include "ccont.h" +#include "../../gui/SignalIDs.h" +#include "ksysguardd.h" + +#include "Command.h" +#include "ProcessList.h" + +#define BUFSIZE 1024 +#define KDEINITLEN strlen("kdeinit: ") + +typedef struct { + int alive; /* for "garbage collection" */ + pid_t pid; /* process ID */ + pid_t ppid; /* parent process ID */ + uid_t uid; /* process owner (real UID) */ + gid_t gid; /* process group (real GID) */ + char *userName; /* process owner (name) */ + int nThreads; /* # of threads in this process */ + int Prio; /* scheduling priority */ + size_t Size; /* total size of process image */ + size_t RSSize; /* resident set size */ + char State[8]; /* process state */ + double Time; /* CPU time for the process in 100ms */ + double Load; /* CPU load in % */ + char Command[PRCOMSIZ];/* command name */ + char CmdLine[PRARGSZ];/* command line */ + double centStamp; /* timestamp for CPU load */ +} ProcessInfo; + +static CONTAINER ProcessList = 0; +static unsigned ProcessCount = 0; /* # of processes */ +static DIR *procdir; /* handle for /proc */ +static int pagesz; + +#define KBYTES 1024 + +/* + * lwpStateName() -- return string representation of process state + */ +char *lwpStateName( prpsinfo_t lwpinfo ) { + + static char result[8]; + + switch( lwpinfo.pr_sname ) { + case 'S': + sprintf( result, "%s", "sleep" ); + break; + case 'R': + sprintf( result, "%s", "run" ); + break; + case 'Z': + sprintf( result, "%s", "zombie" ); + break; + case 'T': + sprintf( result, "%s", "stop" ); + break; + case 'I': + sprintf( result, "%s", "start" ); + break; + case 'X': + sprintf( result, "%s", "wmem" ); + case '0': + sprintf( result, "%s/%d", "cpu", (int) lwpinfo.pr_sonproc ); + break; + default: + sprintf( result, "%s", "???" ); + break; + } + + return( result ); +} + +static void validateStr( char *string ) { + + char *ptr = string; + + /* + * remove all chars that might screw up communication + */ + while( *ptr != '\0' ) { + if( *ptr == '\t' || *ptr == '\n' || *ptr == '\r' ) + *ptr = ' '; + ptr++; + } + /* + * make sure there's at least one char + */ + if( string[0] == '\0' ) + strcpy( string, " " ); +} + +static int processCmp( void *p1, void *p2 ) { + + return( ((ProcessInfo *) p1)->pid - ((ProcessInfo *) p2)->pid ); +} + +static ProcessInfo *findProcessInList( pid_t pid ) { + + ProcessInfo key; + long index; + + key.pid = pid; + if( (index = search_ctnr( ProcessList, processCmp, &key )) < 0 ) + return( NULL ); + + return( get_ctnr( ProcessList, index )); +} + +static int updateProcess( pid_t pid ) { + ProcessInfo *ps; + int fd; + char buf[BUFSIZE]; + prpsinfo_t psinfo; + struct passwd *pw; + register double newCentStamp,timeDiff, usDiff,usTime; + struct timeval tv; + + if( (ps = findProcessInList( pid )) == NULL ) { + if( (ps = (ProcessInfo *) malloc( sizeof( ProcessInfo ))) + == NULL ) { + print_error( "cannot malloc()\n" ); + return( -1 ); + } + ps->pid = pid; + ps->userName = NULL; + ps->alive = 0; + + gettimeofday(&tv, 0); + ps->centStamp = (double)tv.tv_sec * 100.0 + (double)tv.tv_usec / 10000.0; + + push_ctnr( ProcessList, ps ); + bsort_ctnr( ProcessList, processCmp ); + } + + sprintf( buf, "%s/pinfo/%ld", PROCDIR, pid ); + if( (fd = open( buf, O_RDONLY )) < 0 ) { + /* process terminated */ + return( -1 ); + } + + + + if( ioctl(fd,PIOCPSINFO,&psinfo) < 0) { + print_error( "cannot read psinfo from \"%s\"\n", buf ); + close( fd ); + return( -1 ); + } + close( fd ); + + ps->ppid = psinfo.pr_ppid; + ps->uid = psinfo.pr_uid; + ps->gid = psinfo.pr_gid; + + pw = getpwuid( psinfo.pr_uid ); + if( ps->userName != NULL ) + free( ps->userName ); + ps->userName = strdup( pw->pw_name ); + + strncpy (ps->State,lwpStateName( psinfo ),8); + ps->State[7]='\0'; + + + ps->Prio = psinfo.pr_pri; + + gettimeofday(&tv, 0); + newCentStamp = (double)tv.tv_sec * 100.0 + (double) tv.tv_usec / 10000.0; + usTime = (double) psinfo.pr_time.tv_sec * 100.0 + (double)psinfo.pr_time.tv_nsec / 10000000.0; + + timeDiff = newCentStamp - ps->centStamp; + usDiff = usTime - ps->Time; + + if ((timeDiff > 0.0) && (usDiff >= 0.0)) + { + ps->Load = (usDiff / timeDiff) * 100.0; + /* During startup we get bigger loads since the time diff + * cannot be correct. So we force it to 0. */ + ps->Load = (ps->Load > 100.0) ? 0.0 : ps->Load; + } + else + ps->Load = 0.0; + + ps->centStamp = newCentStamp; + ps->Time = usTime; + + ps->Size = (psinfo.pr_size * pagesz)/KBYTES; + ps->RSSize = (psinfo.pr_rssize * pagesz)/KBYTES; + + strncpy(ps->Command,psinfo.pr_fname,PRCOMSIZ); + ps->Command[PRCOMSIZ-1]='\0'; + + strncpy(ps->CmdLine,psinfo.pr_psargs,PRARGSZ); + ps->CmdLine[PRARGSZ-1]='\0'; + + validateStr( ps->Command ); + validateStr( ps->CmdLine ); + + ps->alive = 1; + return( 0 ); +} + +static void cleanupProcessList( void ) { + + ProcessInfo *ps; + + ProcessCount = 0; + for( ps = first_ctnr( ProcessList ); ps; ps = next_ctnr( ProcessList )) { + if( ps->alive ) { + ps->alive = 0; + ProcessCount++; + } else { + free( remove_ctnr( ProcessList )); + } + } +} + +void initProcessList( struct SensorModul* sm ) { + + if( (procdir = opendir( PROCDIR )) == NULL ) { + print_error( "cannot open \"%s\" for reading\n", PROCDIR ); + return; + } + pagesz=getpagesize(); + ProcessList = new_ctnr(); + updateProcessList(); + + /* + * register the supported monitors & commands + */ + registerMonitor( "pscount", "integer", + printProcessCount, printProcessCountInfo, sm ); + registerMonitor( "ps", "table", + printProcessList, printProcessListInfo, sm ); + + if (!RunAsDaemon) + { + registerCommand("kill", killProcess); + registerCommand("setpriority", setPriority); + } +} + +void exitProcessList( void ) { + + removeMonitor("ps"); + removeMonitor("pscount"); + + if (!RunAsDaemon) + { + removeCommand("kill"); + removeCommand("setpriority"); + } + + destr_ctnr( ProcessList, free ); +} + +int updateProcessList( void ) { + + struct dirent *de; + struct statfs sf; + + statfs("/proc/pinfo",&sf,sizeof(sf),0); + ProcessCount = sf.f_files; + + rewinddir( procdir ); + while( (de = readdir( procdir )) != NULL ) { + /* + * skip '.' and '..' + */ + if( de->d_name[0] == '.' ) + continue; + + /* + * fetch the process info and insert it into the info table + */ + updateProcess( (pid_t) atol( de->d_name )); + } + cleanupProcessList(); + + return( 0 ); +} + +void printProcessListInfo( const char *cmd ) { + fprintf(CurrentClient, "Name\tPID\tPPID\tGID\tStatus\tUser" + "\tSize\tResident\t%% CPU\tPriority\tCommand\n" ); + fprintf(CurrentClient, "s\td\td\td\ts\ts\tD\tD\tf\td\ts\n" ); +} + +void printProcessList( const char *cmd ) { + + ProcessInfo *ps; + + for( ps = first_ctnr( ProcessList ); ps; ps = next_ctnr( ProcessList )) { + fprintf(CurrentClient, + "%s\t%ld\t%ld\t%ld\t%s\t%s\t%d\t%d\t%.2f\t%d\t%s\n", + ps->Command, + (long) ps->pid, + (long) ps->ppid, + (long) ps->gid, + ps->State, + ps->userName, + ps->Size, + ps->RSSize, + ps->Load, + ps->Prio, + ps->CmdLine); + } + + fprintf(CurrentClient, "\n"); +} + +void printProcessCount( const char *cmd ) { + fprintf(CurrentClient, "%d\n", ProcessCount ); +} + +void printProcessCountInfo( const char *cmd ) { + fprintf(CurrentClient, "Number of Processes\t0\t0\t\n" ); +} + +void killProcess( const char *cmd ) { + + int sig, pid; + + sscanf( cmd, "%*s %d %d", &pid, &sig ); + + switch( sig ) { + case MENU_ID_SIGABRT: + sig = SIGABRT; + break; + case MENU_ID_SIGALRM: + sig = SIGALRM; + break; + case MENU_ID_SIGCHLD: + sig = SIGCHLD; + break; + case MENU_ID_SIGCONT: + sig = SIGCONT; + break; + case MENU_ID_SIGFPE: + sig = SIGFPE; + break; + case MENU_ID_SIGHUP: + sig = SIGHUP; + break; + case MENU_ID_SIGILL: + sig = SIGILL; + break; + case MENU_ID_SIGINT: + sig = SIGINT; + break; + case MENU_ID_SIGKILL: + sig = SIGKILL; + break; + case MENU_ID_SIGPIPE: + sig = SIGPIPE; + break; + case MENU_ID_SIGQUIT: + sig = SIGQUIT; + break; + case MENU_ID_SIGSEGV: + sig = SIGSEGV; + break; + case MENU_ID_SIGSTOP: + sig = SIGSTOP; + break; + case MENU_ID_SIGTERM: + sig = SIGTERM; + break; + case MENU_ID_SIGTSTP: + sig = SIGTSTP; + break; + case MENU_ID_SIGTTIN: + sig = SIGTTIN; + break; + case MENU_ID_SIGTTOU: + sig = SIGTTOU; + break; + case MENU_ID_SIGUSR1: + sig = SIGUSR1; + break; + case MENU_ID_SIGUSR2: + sig = SIGUSR2; + break; + } + if( kill( (pid_t) pid, sig )) { + switch( errno ) { + case EINVAL: + fprintf(CurrentClient, "4\n" ); + break; + case ESRCH: + fprintf(CurrentClient, "3\n" ); + break; + case EPERM: + fprintf(CurrentClient, "2\n" ); + break; + default: + fprintf(CurrentClient, "1\n" ); /* unknown error */ + break; + } + } else + fprintf(CurrentClient, "0\n"); +} + +void setPriority( const char *cmd ) { + int pid, prio; + + sscanf( cmd, "%*s %d %d", &pid, &prio ); + if( setpriority( PRIO_PROCESS, pid, prio )) { + switch( errno ) { + case EINVAL: + fprintf(CurrentClient, "4\n" ); + break; + case ESRCH: + fprintf(CurrentClient, "3\n" ); + break; + case EPERM: + case EACCES: + fprintf(CurrentClient, "2\n" ); + break; + default: + fprintf(CurrentClient, "1\n" ); /* unknown error */ + break; + } + } else + fprintf(CurrentClient, "0\n"); +} diff --git a/ksysguard/ksysguardd/Irix/ProcessList.h b/ksysguard/ksysguardd/Irix/ProcessList.h new file mode 100644 index 000000000..5d949279e --- /dev/null +++ b/ksysguard/ksysguardd/Irix/ProcessList.h @@ -0,0 +1,43 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@kde.org> + + Irix support by Carsten Kroll <ckroll@pinnaclesys.com> + + 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 _ProcessList_H_ +#define _ProcessList_H_ + +#define PROCDIR "/proc" + +void initProcessList(struct SensorModul* sm); +void exitProcessList(void); + +int updateProcessList(void); + +void printProcessList(const char*); +void printProcessListInfo(const char*); + +void printProcessCount(const char* cmd); +void printProcessCountInfo(const char* cmd); + +void killProcess(const char* cmd); +void setPriority(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/Irix/cpu.c b/ksysguard/ksysguardd/Irix/cpu.c new file mode 100644 index 000000000..9fdd25ab7 --- /dev/null +++ b/ksysguard/ksysguardd/Irix/cpu.c @@ -0,0 +1,262 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@kde.org> + + Irix support by Carsten Kroll <ckroll@pinnaclesys.com> + + 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/sysmp.h> +#include <sys/sysinfo.h> + +#include "cpu.h" +#include "Command.h" +#include "ksysguardd.h" + +#define CPUSTATES 6 + +long percentages(int cnt, int *out, long *new, long *old, long *diffs); + +static int nCPUs=0; + + +long cp_time[CPUSTATES]; +long cp_old[CPUSTATES]; +long cp_diff[CPUSTATES]; +int cpu_states[CPUSTATES]; + +struct cpu_info{ + long cp_time[CPUSTATES]; + long cp_old[CPUSTATES]; + long cp_diff[CPUSTATES]; + int cpu_states[CPUSTATES]; +}; + +static struct cpu_info *g_ci; + +/* returns the requested cpu number starting at 0*/ +int getID(const char *cmd){ + int id; + sscanf(cmd + 7, "%d", &id); + return id-1; +} + +void +initCpuInfo(struct SensorModul* sm) +{ + char mname[50]; + int i; + if (sysmp(MP_NPROCS,&nCPUs) < 0) nCPUs=0; + nCPUs++; + g_ci = malloc(sizeof(struct cpu_info) * nCPUs); + memset(g_ci,0,sizeof(struct cpu_info) * nCPUs); + + registerMonitor("cpu/user", "integer", printCPUUser, + printCPUUserInfo, sm); + registerMonitor("cpu/sys", "integer", printCPUSys, + printCPUSysInfo, sm); + registerMonitor("cpu/idle", "integer", printCPUIdle, + printCPUIdleInfo, sm); + + if (nCPUs > 1) for (i=0;i<nCPUs;i++){ + /* indidividual CPU load */ + sprintf(mname,"cpu/cpu%d/user",i+1); + registerMonitor(mname, "integer", printCPUxUser, + printCPUUserInfo, sm); + sprintf(mname,"cpu/cpu%d/sys",i+1); + registerMonitor(mname, "integer", printCPUxSys, + printCPUSysInfo, sm); + sprintf(mname,"cpu/cpu%d/idle",i+1); + registerMonitor(mname, "integer", printCPUxIdle, + printCPUIdleInfo, sm); + } + + updateCpuInfo(); +} + +void +exitCpuInfo(void) +{ + free(g_ci); +} + +int +updateCpuInfo(void) +{ + struct sysinfo si; + int rv=0; + int i; + /* overall summary */ + if (sysmp(MP_SAGET,MPSA_SINFO,&si,sizeof(struct sysinfo)) >=0){ + cp_time[CPU_IDLE] =si.cpu[CPU_IDLE]; + cp_time[CPU_USER] =si.cpu[CPU_USER]; + cp_time[CPU_KERNEL]=si.cpu[CPU_KERNEL]; + cp_time[CPU_SXBRK] =si.cpu[CPU_SXBRK]; + cp_time[CPU_INTR] =si.cpu[CPU_INTR]; + cp_time[CPU_WAIT] =si.cpu[CPU_WAIT]; + percentages(CPUSTATES,cpu_states,cp_time,cp_old,cp_diff); + } + /* individual CPU statistics*/ + if (nCPUs > 1) for (i=0;i<nCPUs;i++){ + if (sysmp(MP_SAGET1,MPSA_SINFO,&si,sizeof(struct sysinfo),i) >=0){ + g_ci[i].cp_time[CPU_IDLE] =si.cpu[CPU_IDLE]; + g_ci[i].cp_time[CPU_USER] =si.cpu[CPU_USER]; + g_ci[i].cp_time[CPU_KERNEL]=si.cpu[CPU_KERNEL]; + g_ci[i].cp_time[CPU_SXBRK] =si.cpu[CPU_SXBRK]; + g_ci[i].cp_time[CPU_INTR] =si.cpu[CPU_INTR]; + g_ci[i].cp_time[CPU_WAIT] =si.cpu[CPU_WAIT]; + percentages(CPUSTATES, g_ci[i].cpu_states, g_ci[i].cp_time, g_ci[i].cp_old,g_ci[i].cp_diff); + }else{ + rv =-1; + } + } + return (rv); +} + +void +printCPUUser(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", cpu_states[CPU_USER]/10); +} + +void +printCPUUserInfo(const char* cmd) +{ + fprintf(CurrentClient, "CPU User Load\t0\t100\t%%\n"); +} + +void +printCPUSys(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", cpu_states[CPU_KERNEL]/10); +} + +void +printCPUSysInfo(const char* cmd) +{ + fprintf(CurrentClient, "CPU System Load\t0\t100\t%%\n"); +} + +void +printCPUIdle(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", cpu_states[CPU_IDLE]/10); +} + +void +printCPUIdleInfo(const char* cmd) +{ + fprintf(CurrentClient, "CPU Idle Load\t0\t100\t%%\n"); +} +/* same as above but for individual CPUs */ +void +printCPUxUser(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", g_ci[getID(cmd)].cpu_states[CPU_USER]/10); +} + +void +printCPUxSys(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", g_ci[getID(cmd)].cpu_states[CPU_KERNEL]/10); +} + +void +printCPUxIdle(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", g_ci[getID(cmd)].cpu_states[CPU_IDLE]/10); +} + + +/* The part ripped from top... */ +/* + * Top users/processes display for Unix + * Version 3 + * + * This program may be freely redistributed, + * but this entire comment MUST remain intact. + * + * Copyright (c) 1984, 1989, William LeFebvre, Rice University + * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University + */ + +/* + * percentages(cnt, out, new, old, diffs) - calculate percentage change + * between array "old" and "new", putting the percentages in "out". + * "cnt" is size of each array and "diffs" is used for scratch space. + * The array "old" is updated on each call. + * The routine assumes modulo arithmetic. This function is especially + * useful on BSD mchines for calculating cpu state percentages. + */ + +long percentages(cnt, out, new, old, diffs) + +int cnt; +int *out; +register long *new; +register long *old; +long *diffs; + +{ + register int i; + register long change; + register long total_change; + register long *dp; + long half_total; + + /* initialization */ + total_change = 0; + dp = diffs; + + /* calculate changes for each state and the overall change */ + for (i = 0; i < cnt; i++) + { + if ((change = *new - *old) < 0) + { + /* this only happens when the counter wraps */ + change = (int) + ((unsigned long)*new-(unsigned long)*old); + } + total_change += (*dp++ = change); + *old++ = *new++; + } + + /* avoid divide by zero potential */ + if (total_change == 0) + { + total_change = 1; + } + + /* calculate percentages based on overall change, rounding up */ + half_total = total_change / 2l; + + /* Do not divide by 0. Causes Floating point exception */ + if(total_change) { + for (i = 0; i < cnt; i++) + { + *out++ = (int)((*diffs++ * 1000 + half_total) / total_change); + } + } + + /* return the total in case the caller wants to use it */ + return(total_change); +} diff --git a/ksysguard/ksysguardd/Irix/cpu.h b/ksysguard/ksysguardd/Irix/cpu.h new file mode 100644 index 000000000..f61d12505 --- /dev/null +++ b/ksysguard/ksysguardd/Irix/cpu.h @@ -0,0 +1,43 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@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 _cpuinfo_h_ +#define _cpuinfo_h_ + +void initCpuInfo(struct SensorModul* sm); +void exitCpuInfo(void); + +int updateCpuInfo(void); + +void printCPUUser(const char* cmd); +void printCPUUserInfo(const char* cmd); +void printCPUSys(const char* cmd); +void printCPUSysInfo(const char* cmd); +void printCPUIdle(const char* cmd); +void printCPUIdleInfo(const char* cmd); +void printCPUxUser(const char* cmd); +void printCPUxUserInfo(const char* cmd); +void printCPUxSys(const char* cmd); +void printCPUxSysInfo(const char* cmd); +void printCPUxIdle(const char* cmd); +void printCPUxIdleInfo(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/Linux/Makefile.am b/ksysguard/ksysguardd/Linux/Makefile.am new file mode 100644 index 000000000..928b4b66a --- /dev/null +++ b/ksysguard/ksysguardd/Linux/Makefile.am @@ -0,0 +1,14 @@ +AM_CPPFLAGS = -D_GNU_SOURCE +AM_CFLAGS = -Wall + +# add all supported modules +if supports_i8k +KSGRD_SUPPORTS = -DHAVE_I8K_SUPPORT +endif + + +INCLUDES = -I$(srcdir)/../../CContLib -I$(srcdir)/.. $(KSGRD_SUPPORTS) $(all_includes) + +noinst_LIBRARIES = libksysguardd.a +libksysguardd_a_SOURCES = ProcessList.c Memory.c stat.c netdev.c apm.c acpi.c \ + loadavg.c cpuinfo.c lmsensors.c netstat.c diskstat.c logfile.c i8k.c diff --git a/ksysguard/ksysguardd/Linux/Memory.c b/ksysguard/ksysguardd/Linux/Memory.c new file mode 100644 index 000000000..93c8d9edb --- /dev/null +++ b/ksysguard/ksysguardd/Linux/Memory.c @@ -0,0 +1,293 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "Command.h" +#include "ksysguardd.h" + +#include "Memory.h" + +#define MEMINFOBUFSIZE (2 * 1024) + +static char MemInfoBuf[ MEMINFOBUFSIZE ]; +static int Dirty = 1; + +static unsigned long Total = 0; +static unsigned long MFree = 0; +static unsigned long Appl = 0; +static unsigned long Used = 0; +static unsigned long Buffers = 0; +static unsigned long Cached = 0; +static unsigned long STotal = 0; +static unsigned long SFree = 0; +static unsigned long SUsed = 0; + +static void scan_one( const char* buff, const char *key, unsigned long int* val ) +{ + int o; + char *b = strstr( buff, key ); + if ( b ) + o = sscanf( b + strlen( key ), ": %lu", val ); +} + +static void processMemInfo() +{ + scan_one( MemInfoBuf, "MemTotal", &Total ); + scan_one( MemInfoBuf, "MemFree", &MFree ); + scan_one( MemInfoBuf, "Buffers", &Buffers ); + scan_one( MemInfoBuf, "Cached", &Cached ); + scan_one( MemInfoBuf, "SwapTotal", &STotal ); + scan_one( MemInfoBuf, "SwapFree", &SFree ); + Used = Total - MFree; + Appl = ( Used - ( Buffers + Cached ) ); + + if ( STotal == 0 ) /* no swap activated */ + SUsed = 0; + else + SUsed = STotal - SFree; + + Dirty = 0; +} + +/* +================================ public part ================================= +*/ + +void initMemory( struct SensorModul* sm ) +{ + /** + Make sure that /proc/meminfo exists and is readable. If not we do + not register any monitors for memory. + */ + if ( updateMemory() < 0 ) + return; + + registerMonitor( "mem/physical/free", "integer", printMFree, printMFreeInfo, sm ); + registerMonitor( "mem/physical/used", "integer", printUsed, printUsedInfo, sm ); + registerMonitor( "mem/physical/application", "integer", printAppl, printApplInfo, sm ); + registerMonitor( "mem/physical/buf", "integer", printBuffers, printBuffersInfo, sm ); + registerMonitor( "mem/physical/cached", "integer", printCached, printCachedInfo, sm ); + registerMonitor( "mem/swap/used", "integer", printSwapUsed, printSwapUsedInfo, sm ); + registerMonitor( "mem/swap/free", "integer", printSwapFree, printSwapFreeInfo, sm ); +} + +void exitMemory( void ) +{ +} + +int updateMemory( void ) +{ + /** + The amount of total and used memory is read from the /proc/meminfo. + It also contains the information about the swap space. + The 'file' looks like this: + + MemTotal: 516560 kB + MemFree: 7812 kB + MemShared: 0 kB + Buffers: 80312 kB + Cached: 236432 kB + SwapCached: 468 kB + Active: 291992 kB + Inactive: 133556 kB + HighTotal: 0 kB + HighFree: 0 kB + LowTotal: 516560 kB + LowFree: 7812 kB + SwapTotal: 899632 kB + SwapFree: 898932 kB + Dirty: 2736 kB + Writeback: 0 kB + Mapped: 155996 kB + Slab: 73920 kB + Committed_AS: 315588 kB + PageTables: 1764 kB + ReverseMaps: 103458 + */ + + int fd; + size_t n; + + if ( ( fd = open( "/proc/meminfo", O_RDONLY ) ) < 0 ) { + print_error( "Cannot open \'/proc/meminfo\'!\n" + "The kernel needs to be compiled with support\n" + "for /proc filesystem enabled!\n" ); + return -1; + } + + if ( ( n = read( fd, MemInfoBuf, MEMINFOBUFSIZE - 1 ) ) == MEMINFOBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'/proc/mem\'" ); + close( fd ); + return -1; + } + + close( fd ); + MemInfoBuf[ n ] = '\0'; + Dirty = 1; + + return 0; +} + +void printMFree( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processMemInfo(); + + fprintf( CurrentClient, "%ld\n", MFree ); +} + +void printMFreeInfo( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processMemInfo(); + + fprintf( CurrentClient, "Free Memory\t0\t%ld\tKB\n", Total ); +} + +void printUsed( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processMemInfo(); + + fprintf( CurrentClient, "%ld\n", Used ); +} + +void printUsedInfo( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processMemInfo(); + + fprintf( CurrentClient, "Used Memory\t0\t%ld\tKB\n", Total ); +} + +void printAppl( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processMemInfo(); + + fprintf( CurrentClient, "%ld\n", Appl ); +} + +void printApplInfo( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processMemInfo(); + + fprintf( CurrentClient, "Application Memory\t0\t%ld\tKB\n", Total ); +} + +void printBuffers( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processMemInfo(); + + fprintf( CurrentClient, "%ld\n", Buffers ); +} + +void printBuffersInfo( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processMemInfo(); + + fprintf( CurrentClient, "Buffer Memory\t0\t%ld\tKB\n", Total ); +} + +void printCached( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processMemInfo(); + + fprintf( CurrentClient, "%ld\n", Cached ); +} + +void printCachedInfo( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processMemInfo(); + + fprintf( CurrentClient, "Cached Memory\t0\t%ld\tKB\n", Total ); +} + +void printSwapUsed( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processMemInfo(); + + fprintf( CurrentClient, "%ld\n", SUsed ); +} + +void printSwapUsedInfo( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processMemInfo(); + + fprintf( CurrentClient, "Used Swap Memory\t0\t%ld\tKB\n", STotal ); +} + +void printSwapFree( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processMemInfo(); + + fprintf( CurrentClient, "%ld\n", SFree ); +} + +void printSwapFreeInfo( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processMemInfo(); + + fprintf( CurrentClient, "Free Swap Memory\t0\t%ld\tKB\n", STotal ); +} diff --git a/ksysguard/ksysguardd/Linux/Memory.h b/ksysguard/ksysguardd/Linux/Memory.h new file mode 100644 index 000000000..2dbd6f2dc --- /dev/null +++ b/ksysguard/ksysguardd/Linux/Memory.h @@ -0,0 +1,45 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@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 KSG_MEMORY_H +#define KSG_MEMORY_H + +void initMemory( struct SensorModul* ); +void exitMemory( void ); + +int updateMemory( void ); + +void printMFree( const char* ); +void printMFreeInfo( const char* ); +void printUsed( const char* ); +void printUsedInfo( const char* ); +void printAppl( const char* ); +void printApplInfo( const char* ); +void printBuffers( const char* ); +void printBuffersInfo( const char* ); +void printCached( const char* ); +void printCachedInfo( const char* ); +void printSwapUsed( const char* ); +void printSwapUsedInfo( const char* ); +void printSwapFree( const char* ); +void printSwapFreeInfo( const char* ); + +#endif diff --git a/ksysguard/ksysguardd/Linux/ProcessList.c b/ksysguard/ksysguardd/Linux/ProcessList.c new file mode 100644 index 000000000..b267c7005 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/ProcessList.c @@ -0,0 +1,554 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <time.h> +#include <unistd.h> + +#include "../../gui/SignalIDs.h" +#include "Command.h" +#include "PWUIDCache.h" +#include "ccont.h" +#include "ksysguardd.h" + +#include "ProcessList.h" + +#define BUFSIZE 1024 +#define TAGSIZE 32 +#define KDEINITLEN strlen( "kdeinit: " ) + +static CONTAINER ProcessList = 0; + +typedef struct { + /** + This flag is set for all found processes at the beginning of the + process list update. Processes that do not have this flag set will + be assumed dead and removed from the list. The flag is cleared after + each list update. + */ + int alive; + + /* The process ID */ + pid_t pid; + + /* The parent process ID */ + pid_t ppid; + + /* The real user ID */ + uid_t uid; + + /* The real group ID */ + gid_t gid; + + /* A character description of the process status */ + char status[ 16 ]; + + /* The number of the tty the process owns */ + int ttyNo; + + /** + The nice level. The range should be -20 to 20. I'm not sure + whether this is true for all platforms. + */ + int niceLevel; + + /* The scheduling priority. */ + int priority; + + /** + The total amount of memory the process uses. This includes shared and + swapped memory. + */ + unsigned int vmSize; + + /* The amount of physical memory the process currently uses. */ + unsigned int vmRss; + + /** + The number of 1/100 of a second the process has spend in user space. + If a machine has an uptime of 1 1/2 years or longer this is not a + good idea. I never thought that the stability of UNIX could get me + into trouble! ;) + */ + unsigned int userTime; + + /** + The number of 1/100 of a second the process has spend in system space. + If a machine has an uptime of 1 1/2 years or longer this is not a + good idea. I never thought that the stability of UNIX could get me + into trouble! ;) + */ + unsigned int sysTime; + + /* The system time as multime of 100ms */ + int centStamp; + + /* The current CPU load (in %) from user space */ + double userLoad; + + /* The current CPU load (in %) from system space */ + double sysLoad; + + /* The name of the process */ + char name[ 64 ]; + + /* The command used to start the process */ + char cmdline[ 256 ]; + + /* The login name of the user that owns this process */ + char userName[ 32 ]; +} ProcessInfo; + +static unsigned ProcessCount; + +static void validateStr( char* str ) +{ + char* s = str; + + /* All characters that could screw up the communication will be removed. */ + while ( *s ) { + if ( *s == '\t' || *s == '\n' || *s == '\r' ) + *s = ' '; + ++s; + } + + /* Make sure that string contains at least one character (blank). */ + if ( str[ 0 ] == '\0' ) + strcpy( str, " " ); +} + +static int processCmp( void* p1, void* p2 ) +{ + return ( ((ProcessInfo*)p1)->pid - ((ProcessInfo*)p2)->pid ); +} + +static ProcessInfo* findProcessInList( int pid ) +{ + ProcessInfo key; + long idx; + + key.pid = pid; + if ( ( idx = search_ctnr( ProcessList, processCmp, &key ) ) < 0 ) + return 0; + + return get_ctnr( ProcessList, idx ); +} + +static int updateProcess( int pid ) +{ + ProcessInfo* ps; + FILE* fd; + char buf[ BUFSIZE ]; + char tag[ TAGSIZE ]; + char format[ 32 ]; + char tagformat[ 32 ]; + int userTime, sysTime; + const char* uName; + char status; + + if ( ( ps = findProcessInList( pid ) ) == 0 ) { + struct timeval tv; + + ps = (ProcessInfo*)malloc( sizeof( ProcessInfo ) ); + ps->pid = pid; + ps->alive = 0; + + gettimeofday( &tv, 0 ); + ps->centStamp = tv.tv_sec * 100 + tv.tv_usec / 10000; + + push_ctnr( ProcessList, ps ); + bsort_ctnr( ProcessList, processCmp ); + } + + snprintf( buf, BUFSIZE - 1, "/proc/%d/status", pid ); + if ( ( fd = fopen( buf, "r" ) ) == 0 ) { + /* process has terminated in the mean time */ + return -1; + } + + sprintf( format, "%%%d[^\n]\n", (int)sizeof( buf ) - 1 ); + sprintf( tagformat, "%%%ds", (int)sizeof( tag ) - 1 ); + for ( ;; ) { + if ( fscanf( fd, format, buf ) != 1 ) + break; + buf[ sizeof( buf ) - 1 ] = '\0'; + sscanf( buf, tagformat, tag ); + tag[ sizeof( tag ) - 1 ] = '\0'; + if ( strcmp( tag, "Name:" ) == 0 ) { + sscanf( buf, "%*s %63s", ps->name ); + validateStr( ps->name ); + } else if ( strcmp( tag, "Uid:" ) == 0 ) + sscanf( buf, "%*s %d %*d %*d %*d", (int*)&ps->uid ); + } + + if ( fclose( fd ) ) + return -1; + + snprintf( buf, BUFSIZE - 1, "/proc/%d/stat", pid ); + buf[ BUFSIZE - 1 ] = '\0'; + if ( ( fd = fopen( buf, "r" ) ) == 0 ) + return -1; + + if ( fscanf( fd, "%*d %*s %c %d %d %*d %d %*d %*u %*u %*u %*u %*u %d %d" + "%*d %*d %*d %d %*u %*u %*d %u %u", + &status, (int*)&ps->ppid, (int*)&ps->gid, &ps->ttyNo, + &userTime, &sysTime, &ps->niceLevel, &ps->vmSize, + &ps->vmRss) != 9 ) { + fclose( fd ); + return -1; + } + + if ( fclose( fd ) ) + return -1; + + /* status decoding as taken from fs/proc/array.c */ + if ( status == 'R' ) + strcpy( ps->status, "running" ); + else if ( status == 'S' ) + strcpy( ps->status, "sleeping" ); + else if ( status == 'D' ) + strcpy( ps->status, "disk sleep" ); + else if ( status == 'Z' ) + strcpy( ps->status, "zombie" ); + else if ( status == 'T' ) + strcpy( ps->status, "stopped" ); + else if ( status == 'W' ) + strcpy( ps->status, "paging" ); + else + sprintf( ps->status, "Unknown: %c", status ); + + ps->vmRss = ( ps->vmRss + 3 ) * sysconf(_SC_PAGESIZE); + + { + int newCentStamp; + int timeDiff, userDiff, sysDiff; + struct timeval tv; + + gettimeofday( &tv, 0 ); + newCentStamp = tv.tv_sec * 100 + tv.tv_usec / 10000; + + timeDiff = newCentStamp - ps->centStamp; + userDiff = userTime - ps->userTime; + sysDiff = sysTime - ps->sysTime; + + if ( ( timeDiff > 0 ) && ( userDiff >= 0 ) && ( sysDiff >= 0 ) ) { + ps->userLoad = ( (double)userDiff / timeDiff ) * 100.0; + ps->sysLoad = ( (double)sysDiff / timeDiff ) * 100.0; + /** + During startup we get bigger loads since the time diff + cannot be correct. So we force it to 0. + */ + if ( ps->userLoad > 100.0 ) + ps->userLoad = 0.0; + if ( ps->sysLoad > 100.0 ) + ps->sysLoad = 0.0; + } else + ps->sysLoad = ps->userLoad = 0.0; + + ps->centStamp = newCentStamp; + ps->userTime = userTime; + ps->sysTime = sysTime; + } + + snprintf( buf, BUFSIZE - 1, "/proc/%d/cmdline", pid ); + if ( ( fd = fopen( buf, "r" ) ) == 0 ) + return -1; + + ps->cmdline[ 0 ] = '\0'; + sprintf( buf, "%%%d[^\n]", (int)sizeof( ps->cmdline ) - 1 ); + fscanf( fd, buf, ps->cmdline ); + ps->cmdline[ sizeof( ps->cmdline ) - 1 ] = '\0'; + validateStr( ps->cmdline ); + if ( fclose( fd ) ) + return -1; + + /* Ugly hack to "fix" program name for kdeinit launched programs. */ + if ( strcmp( ps->name, "kdeinit" ) == 0 && + strncmp( ps->cmdline, "kdeinit: ", KDEINITLEN ) == 0 && + strcmp( ps->cmdline + KDEINITLEN, "Running..." ) != 0 ) { + size_t len; + char* end = strchr( ps->cmdline + KDEINITLEN, ' ' ); + if ( end ) + len = ( end - ps->cmdline ) - KDEINITLEN; + else + len = strlen( ps->cmdline + KDEINITLEN ); + if ( len > 0 ) { + if ( len > sizeof( ps->name ) - 1 ) + len = sizeof( ps->name ) - 1; + strncpy( ps->name, ps->cmdline + KDEINITLEN, len ); + ps->name[ len ] = '\0'; + } + } + + /* find out user name with the process uid */ + uName = getCachedPWUID( ps->uid ); + strncpy( ps->userName, uName, sizeof( ps->userName ) - 1 ); + ps->userName[ sizeof( ps->userName ) - 1 ] = '\0'; + validateStr( ps->userName ); + + ps->alive = 1; + + return 0; +} + +static void cleanupProcessList( void ) +{ + ProcessInfo* ps; + + ProcessCount = 0; + /** + All processes that do not have the active flag set are assumed dead + and will be removed from the list. The alive flag is cleared. + */ + for ( ps = first_ctnr( ProcessList ); ps; ps = next_ctnr( ProcessList ) ) { + if ( ps->alive ) { + /* Process is still alive. Just clear flag. */ + ps->alive = 0; + ProcessCount++; + } else { + /** + Process has probably died. We remove it from the list and + destruct the data structure. i needs to be decremented so + that after i++ the next list element will be inspected. + */ + free( remove_ctnr( ProcessList ) ); + } + } +} + +int updateProcessList( void ) +{ + DIR* dir; + struct dirent* entry; + + /* read in current process list via the /proc filesystem entry */ + if ( ( dir = opendir( "/proc" ) ) == NULL ) { + print_error( "Cannot open directory \'/proc\'!\n" + "The kernel needs to be compiled with support\n" + "for /proc filesystem enabled!\n" ); + return 0; + } + + while ( ( entry = readdir( dir ) ) ) { + if ( isdigit( entry->d_name[ 0 ] ) ) { + int pid; + + pid = atoi( entry->d_name ); + updateProcess( pid ); + } + } + closedir( dir ); + + cleanupProcessList(); + return 0; +} + +/* +================================ public part ================================= +*/ + +void initProcessList( struct SensorModul* sm ) +{ + initPWUIDCache(); + + ProcessList = new_ctnr(); + + registerMonitor( "pscount", "integer", printProcessCount, printProcessCountInfo, sm ); + registerMonitor( "ps", "table", printProcessList, printProcessListInfo, sm ); + + if ( !RunAsDaemon ) { + registerCommand( "kill", killProcess ); + registerCommand( "setpriority", setPriority ); + } + + updateProcessList(); +} + +void exitProcessList( void ) +{ + removeMonitor( "ps" ); + removeMonitor( "pscount" ); + + if ( !RunAsDaemon ) { + removeCommand( "kill" ); + removeCommand( "setpriority" ); + } + + destr_ctnr( ProcessList, free ); + + exitPWUIDCache(); +} + +void printProcessListInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Name\tPID\tPPID\tUID\tGID\tStatus\tUser%%\tSystem%%\tNice\tVmSize" + "\tVmRss\tLogin\tCommand\n" ); + fprintf( CurrentClient, "s\td\td\td\td\tS\tf\tf\td\tD\tD\ts\ts\n" ); +} + +void printProcessList( const char* cmd ) +{ + ProcessInfo* ps; + + (void)cmd; + + for ( ps = first_ctnr( ProcessList ); ps; ps = next_ctnr( ProcessList ) ) { + fprintf( CurrentClient, "%s\t%ld\t%ld\t%ld\t%ld\t%s\t%.2f\t%.2f\t%d\t%d\t%d" + "\t%s\t%s\n", ps->name, (long)ps->pid, (long)ps->ppid, + (long)ps->uid, (long)ps->gid, ps->status, ps->userLoad, + ps->sysLoad, ps->niceLevel, ps->vmSize / 1024, ps->vmRss / 1024, + ps->userName, ps->cmdline ); + } + + fprintf( CurrentClient, "\n" ); +} + +void printProcessCount( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "%d\n", ProcessCount ); +} + +void printProcessCountInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Number of Processes\t0\t0\t\n" ); +} + +void killProcess( const char* cmd ) +{ + int sig, pid; + + sscanf( cmd, "%*s %d %d", &pid, &sig ); + switch( sig ) { + case MENU_ID_SIGABRT: + sig = SIGABRT; + break; + case MENU_ID_SIGALRM: + sig = SIGALRM; + break; + case MENU_ID_SIGCHLD: + sig = SIGCHLD; + break; + case MENU_ID_SIGCONT: + sig = SIGCONT; + break; + case MENU_ID_SIGFPE: + sig = SIGFPE; + break; + case MENU_ID_SIGHUP: + sig = SIGHUP; + break; + case MENU_ID_SIGILL: + sig = SIGILL; + break; + case MENU_ID_SIGINT: + sig = SIGINT; + break; + case MENU_ID_SIGKILL: + sig = SIGKILL; + break; + case MENU_ID_SIGPIPE: + sig = SIGPIPE; + break; + case MENU_ID_SIGQUIT: + sig = SIGQUIT; + break; + case MENU_ID_SIGSEGV: + sig = SIGSEGV; + break; + case MENU_ID_SIGSTOP: + sig = SIGSTOP; + break; + case MENU_ID_SIGTERM: + sig = SIGTERM; + break; + case MENU_ID_SIGTSTP: + sig = SIGTSTP; + break; + case MENU_ID_SIGTTIN: + sig = SIGTTIN; + break; + case MENU_ID_SIGTTOU: + sig = SIGTTOU; + break; + case MENU_ID_SIGUSR1: + sig = SIGUSR1; + break; + case MENU_ID_SIGUSR2: + sig = SIGUSR2; + break; + } + + if ( kill( (pid_t)pid, sig ) ) { + switch ( errno ) { + case EINVAL: + fprintf( CurrentClient, "4\t%d\n", pid ); + break; + case ESRCH: + fprintf( CurrentClient, "3\t%d\n", pid ); + break; + case EPERM: + if(vfork() == 0) { + exit(0);/* Won't execute unless execve fails. Need this for the parent process to continue */ + } + fprintf( CurrentClient, "2\t%d\n", pid ); + break; + default: /* unknown error */ + fprintf( CurrentClient, "1\t%d\n", pid ); + break; + } + } else + fprintf( CurrentClient, "0\t%d\n", pid ); +} + +void setPriority( const char* cmd ) +{ + int pid, prio; + + sscanf( cmd, "%*s %d %d", &pid, &prio ); + if ( setpriority( PRIO_PROCESS, pid, prio ) ) { + switch ( errno ) { + case EINVAL: + fprintf( CurrentClient, "4\n" ); + break; + case ESRCH: + fprintf( CurrentClient, "3\n" ); + break; + case EPERM: + case EACCES: + fprintf( CurrentClient, "2\n" ); + break; + default: /* unknown error */ + fprintf( CurrentClient, "1\n" ); + break; + } + } else + fprintf( CurrentClient, "0\n" ); +} diff --git a/ksysguard/ksysguardd/Linux/ProcessList.h b/ksysguard/ksysguardd/Linux/ProcessList.h new file mode 100644 index 000000000..709994a29 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/ProcessList.h @@ -0,0 +1,38 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2000 Chris Schlaeger <cs@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 KSG_PROCESSLIST_H +#define KSG_PROCESSLIST_H + +void initProcessList( struct SensorModul* ); +void exitProcessList( void ); + +int updateProcessList( void ); + +void printProcessList( const char* ); +void printProcessListInfo( const char* ); +void printProcessCount( const char* ); +void printProcessCountInfo( const char* ); + +void killProcess( const char* ); +void setPriority( const char* ); + +#endif diff --git a/ksysguard/ksysguardd/Linux/acpi.c b/ksysguard/ksysguardd/Linux/acpi.c new file mode 100644 index 000000000..b3100c363 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/acpi.c @@ -0,0 +1,418 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Stephan Uhlmann <su@su2.info> + Copyright (c) 2005 Sirtaj Singh Kang <taj@kde.org> -- Battery fixes and Thermal + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <dirent.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "Command.h" +#include "ksysguardd.h" + +#include "acpi.h" + +#define ACPIFILENAMELENGTHMAX 64 +#define ACPIBATTERYNUMMAX 6 +#define ACPIBATTERYINFOBUFSIZE 1024 +#define ACPIBATTERYSTATEBUFSIZE 512 + +static int AcpiBatteryNum = 0; +static char AcpiBatteryNames[ ACPIBATTERYNUMMAX ][ 8 ]; +static int AcpiBatteryCharge[ ACPIBATTERYNUMMAX ]; +static int AcpiBatteryUsage[ ACPIBATTERYNUMMAX ]; + +static int AcpiThermalZones = -1; +static int AcpiFans = -1; +/* +================================ public part ================================= +*/ + +void initAcpi(struct SensorModul* sm) +{ + initAcpiBattery(sm); + initAcpiFan(sm); + initAcpiThermal(sm); +} + +int updateAcpi( void ) +{ + if (AcpiBatteryNum > 0) updateAcpiBattery(); + if (AcpiFans > 0) updateAcpiFan(); + if (AcpiThermalZones > 0) updateAcpiThermal(); + return 0; +} + +void exitAcpi( void ) +{ + AcpiBatteryNum = -1; + AcpiFans = -1; + AcpiThermalZones = -1; +} + + +/************ ACPI Battery **********/ + +void initAcpiBattery( struct SensorModul* sm ) +{ + DIR *d; + struct dirent *de; + char s[ ACPIFILENAMELENGTHMAX ]; + + if ( ( d = opendir( "/proc/acpi/battery" ) ) == NULL ) { + AcpiBatteryNum = -1; + return; + } else { + AcpiBatteryNum = 0; + while ( ( de = readdir( d ) ) ) + if ( ( strcmp( de->d_name, "." ) != 0 ) && ( strcmp( de->d_name, ".." ) != 0 ) ) { + strncpy( AcpiBatteryNames[ AcpiBatteryNum ], de->d_name, 8 ); + snprintf( s, sizeof( s ), "acpi/battery/%d/batterycharge", AcpiBatteryNum ); + registerMonitor( s, "integer", printAcpiBatFill, printAcpiBatFillInfo, sm ); + snprintf( s, sizeof( s ), "acpi/battery/%d/batteryusage", AcpiBatteryNum ); + registerMonitor( s, "integer", printAcpiBatUsage, printAcpiBatUsageInfo, sm); + AcpiBatteryCharge[ AcpiBatteryNum ] = 0; + AcpiBatteryNum++; + } + } +} + + +int updateAcpiBattery( void ) +{ + int i, fd; + char s[ ACPIFILENAMELENGTHMAX ]; + size_t n; + char AcpiBatInfoBuf[ ACPIBATTERYINFOBUFSIZE ]; + char AcpiBatStateBuf[ ACPIBATTERYSTATEBUFSIZE ]; + char *p; + int AcpiBatCapacity = 1; + int AcpiBatRemainingCapacity = 0; + + if ( AcpiBatteryNum <= 0 ) + return -1; + + for ( i = 0; i < AcpiBatteryNum; i++ ) { + /* get total capacity */ + snprintf( s, sizeof( s ), "/proc/acpi/battery/%s/info", AcpiBatteryNames[ i ] ); + if ( ( fd = open( s, O_RDONLY ) ) < 0 ) { + print_error( "Cannot open file \'%s\'!\n" + "Load the battery ACPI kernel module or\n" + "compile it into your kernel.\n", s ); + return -1; + } + if ( ( n = read( fd, AcpiBatInfoBuf, ACPIBATTERYINFOBUFSIZE - 1 ) ) == + ACPIBATTERYINFOBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'%s\'", s ); + close( fd ); + return -1; + } + close( fd ); + p = AcpiBatInfoBuf; + while ( ( p!= NULL ) && ( sscanf( p, "last full capacity: %d ", + &AcpiBatCapacity ) != 1 ) ) { + p = strchr( p, '\n' ); + if ( p ) + p++; + } + /* get remaining capacity */ + snprintf( s, sizeof( s ), "/proc/acpi/battery/%s/state", AcpiBatteryNames[ i ] ); + if ( ( fd = open( s, O_RDONLY ) ) < 0 ) { + print_error( "Cannot open file \'%s\'!\n" + "Load the battery ACPI kernel module or\n" + "compile it into your kernel.\n", s ); + return -1; + } + if ( ( n = read( fd, AcpiBatStateBuf, ACPIBATTERYSTATEBUFSIZE - 1 ) ) == + ACPIBATTERYSTATEBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'%s\'", s); + close( fd ); + return -1; + } + close( fd ); + p = AcpiBatStateBuf; + while ( ( p!= NULL ) && ( sscanf( p, "remaining capacity: %d ", + &AcpiBatRemainingCapacity ) != 1 ) ) { + p = strchr( p, '\n' ); + if ( p ) + p++; + } + + /* get current battery usage, (current Current) */ + p = AcpiBatStateBuf; + while ( ( p!= NULL ) && ( sscanf( p, "present rate: %d ", + &AcpiBatteryUsage[i] ) != 1 ) ) { + p = strchr( p, '\n' ); + if ( p ) + p++; + } + + + /* calculate charge rate */ + if ( AcpiBatCapacity > 0 ) + AcpiBatteryCharge[ i ] = AcpiBatRemainingCapacity * 100 / AcpiBatCapacity; + else + AcpiBatteryCharge[ i ] = 0; + } + + return 0; +} + +void printAcpiBatFill( const char* cmd ) +{ + int i; + + sscanf( cmd + 13, "%d", &i ); + fprintf( CurrentClient, "%d\n", AcpiBatteryCharge[ i ] ); +} + +void printAcpiBatFillInfo( const char* cmd ) +{ + int i; + + sscanf( cmd + 13, "%d", &i ); + fprintf( CurrentClient, "Battery %d charge\t0\t100\t%%\n", i ); +} + +void printAcpiBatUsage( const char* cmd) +{ + int i; + + sscanf( cmd + 13, "%d", &i ); + fprintf(CurrentClient, "%d\n", AcpiBatteryUsage[ i ] ); +} + +void printAcpiBatUsageInfo( const char* cmd) +{ + + int i; + + sscanf(cmd+13, "%d", &i); + + fprintf(CurrentClient, "Battery %d usage\t0\t2500\tmA\n", i ); +} + +/************** ACPI Thermal *****************/ + +#define THERMAL_ZONE_DIR "/proc/acpi/thermal_zone" +#define TEMPERATURE_FILE "temperature" +#define TEMPERATURE_FILE_MAXLEN 255 + + +/*static char **zone_names = NULL;*/ + +/** Find the thermal zone name from the command. + * Assumes the command is of the form acpi/thermal_zone/<zone name>/... + * @p startidx is set to the start of the zone name. May be set to an + * undefined value if zone name is not found. + * @return length of found name, or 0 if nothing found. + */ +static int extract_zone_name(char **startidx, const char *cmd) +{ + char *idx = NULL; + idx = strchr(cmd, '/'); + if (idx == NULL) return 0; + idx = strchr(idx+1, '/'); + if (idx == NULL) return 0; + *startidx = idx+1; + idx = strchr(*startidx, '/'); + if (idx == NULL) return 0; + return idx - *startidx; +} + +void initAcpiThermal(struct SensorModul *sm) +{ + + char th_ref[ ACPIFILENAMELENGTHMAX ]; + DIR *d = NULL; + struct dirent *de; + + d = opendir(THERMAL_ZONE_DIR); + if (d == NULL) { +/* print_error( "Directory \'" THERMAL_ZONE_DIR + "\' does not exist or is not readable.\n" + "Load the ACPI thermal kernel module or compile it into your kernel.\n" ); +*/ + AcpiThermalZones = -1; + return; + } + + AcpiThermalZones = 0; + while ( (de = readdir(d)) != NULL ) { + if ( ( strcmp( de->d_name, "." ) == 0 ) + || ( strcmp( de->d_name, ".." ) == 0 ) ) { + continue; + } + + AcpiThermalZones++; + snprintf(th_ref, sizeof(th_ref), + "acpi/thermal_zone/%s/temperature", de->d_name); + registerMonitor(th_ref, "integer", printThermalZoneTemperature, + printThermalZoneTemperatureInfo, sm); + } + + return; +} + +int updateAcpiThermal() +{ + /* TODO: stub */ + return 0; +} + +static int getCurrentTemperature(const char *cmd) +{ + char th_file[ ACPIFILENAMELENGTHMAX ]; + char input_buf[ TEMPERATURE_FILE_MAXLEN ]; + char *zone_name = NULL; + int read_bytes = 0, fd = 0, len_zone_name = 0; + int temperature=0; + + len_zone_name = extract_zone_name(&zone_name, cmd); + if (len_zone_name <= 0) return -1; + + snprintf(th_file, sizeof(th_file), + THERMAL_ZONE_DIR "/%.*s/" TEMPERATURE_FILE, + len_zone_name, zone_name); + + fd = open(th_file, O_RDONLY); + if (fd < 0) { + print_error( "Cannot open file \'%s\'!\n" + "Load the thermal ACPI kernel module or\n" + "compile it into your kernel.\n", th_file ); + return -1; + } + + read_bytes = read( fd, input_buf, sizeof(input_buf) - 1 ); + if ( read_bytes == sizeof(input_buf) - 1 ) { + log_error( "Internal buffer too small to read \'%s\'", th_file ); + close( fd ); + return -1; + } + close(fd); + + sscanf(input_buf, "temperature: %d C", &temperature); + return temperature; +} + +void printThermalZoneTemperature(const char *cmd) { + int temperature = getCurrentTemperature(cmd); + fprintf(CurrentClient, "%d\n", temperature); +} + +void printThermalZoneTemperatureInfo(const char *cmd) +{ + fprintf(CurrentClient, "Current temperature\t0\t0\tC\n"); +} + +/********** ACPI Fan State***************/ + +#define FAN_DIR "/proc/acpi/fan" +#define FAN_STATE_FILE "state" +#define FAN_STATE_FILE_MAXLEN 255 + +void initAcpiFan(struct SensorModul *sm) +{ + + char th_ref[ ACPIFILENAMELENGTHMAX ]; + DIR *d = NULL; + struct dirent *de; + + d = opendir(FAN_DIR); + if (d == NULL) { +/* print_error( "Directory \'" THERMAL_ZONE_DIR + "\' does not exist or is not readable.\n" + "Load the ACPI thermal kernel module or compile it into your kernel.\n" ); +*/ + AcpiFans = -1; + return; + } + + AcpiFans = 0; + while ( (de = readdir(d)) != NULL ) { + if ( ( strcmp( de->d_name, "." ) == 0 ) + || ( strcmp( de->d_name, ".." ) == 0 ) ) { + continue; + } + + AcpiFans++; + snprintf(th_ref, sizeof(th_ref), + "acpi/fan/%s/state", de->d_name); + registerMonitor(th_ref, "integer", printFanState, + printFanStateInfo, sm); + } + + return; +} + +int updateAcpiFan() +{ + /* TODO: stub */ + return 0; +} + +static int getFanState(const char *cmd) +{ + char fan_state_file[ ACPIFILENAMELENGTHMAX ]; + char input_buf[ FAN_STATE_FILE_MAXLEN ]; + char *fan_name = NULL; + int read_bytes = 0, fd = 0, len_fan_name = 0; + char fan_state[4]; + + len_fan_name = extract_zone_name(&fan_name, cmd); + if (len_fan_name <= 0) return -1; + + snprintf(fan_state_file, sizeof(fan_state_file), + FAN_DIR "/%.*s/" FAN_STATE_FILE, + len_fan_name, fan_name); + + fd = open(fan_state_file, O_RDONLY); + if (fd < 0) { + print_error( "Cannot open file \'%s\'!\n" + "Load the fan ACPI kernel module or\n" + "compile it into your kernel.\n", fan_state_file ); + return -1; + } + + read_bytes = read( fd, input_buf, sizeof(input_buf) - 1 ); + if ( read_bytes == sizeof(input_buf) - 1 ) { + log_error( "Internal buffer too small to read \'%s\'", fan_state_file ); + close( fd ); + return -1; + } + close(fd); + + sscanf(input_buf, "status: %2s", fan_state); + return (fan_state[1] == 'n') ? 1 : 0; +} + +void printFanState(const char *cmd) { + int fan_state = getFanState(cmd); + fprintf(CurrentClient, "%d\n", fan_state); +} + +void printFanStateInfo(const char *cmd) +{ + fprintf(CurrentClient, "Fan status\t0\t1\tboolean\n"); +} + + diff --git a/ksysguard/ksysguardd/Linux/acpi.h b/ksysguard/ksysguardd/Linux/acpi.h new file mode 100644 index 000000000..ae01ecad1 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/acpi.h @@ -0,0 +1,45 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Stephan Uhlmann <su@su2.info> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_ACPI_H +#define KSG_ACPI_H + +void initAcpi( struct SensorModul* ); +void exitAcpi( void ); + +int updateAcpi( void ); + +void initAcpiBattery( struct SensorModul* ); +int updateAcpiBattery(void); +void printAcpiBatFill( const char* ); +void printAcpiBatFillInfo( const char* ); +void printAcpiBatUsage( const char* ); +void printAcpiBatUsageInfo( const char* ); + +void initAcpiThermal( struct SensorModul * ); +int updateAcpiThermal(void); +void printThermalZoneTemperature(const char *cmd); +void printThermalZoneTemperatureInfo(const char *cmd); + +void initAcpiFan( struct SensorModul * ); +int updateAcpiFan(void); +void printFanState(const char *cmd); +void printFanStateInfo(const char *cmd); + +#endif diff --git a/ksysguard/ksysguardd/Linux/apm.c b/ksysguard/ksysguardd/Linux/apm.c new file mode 100644 index 000000000..0c1d00bcb --- /dev/null +++ b/ksysguard/ksysguardd/Linux/apm.c @@ -0,0 +1,126 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <fcntl.h> +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "Command.h" +#include "ksysguardd.h" + +#include "apm.h" + +static int ApmOK = 0; +static int BatFill, BatTime; + +#define APMBUFSIZE 128 +static char ApmBuf[ APMBUFSIZE ]; +static int Dirty = 0; + +static void processApm( void ) +{ + sscanf( ApmBuf, "%*f %*f %*x %*x %*x %*x %d%% %d min", + &BatFill, &BatTime ); + Dirty = 0; +} + +/* +================================ public part ================================= +*/ + +void initApm( struct SensorModul* sm ) +{ + if ( updateApm() < 0 ) { + ApmOK = -1; + return; + } else + ApmOK = 1; + + registerMonitor( "apm/batterycharge", "integer", printApmBatFill, printApmBatFillInfo, sm ); + registerMonitor( "apm/remainingtime", "integer", printApmBatTime, printApmBatTimeInfo, sm ); +} + +void exitApm( void ) +{ + ApmOK = -1; +} + +int updateApm( void ) +{ + size_t n; + int fd; + + if ( ApmOK < 0 ) + return -1; + + if ( ( fd = open( "/proc/apm", O_RDONLY ) ) < 0 ) { + if ( ApmOK != 0 ) + print_error( "Cannot open file \'/proc/apm\'!\n" + "The kernel needs to be compiled with support\n" + "for /proc filesystem enabled!\n" ); + return -1; + } + + if ( ( n = read( fd, ApmBuf, APMBUFSIZE - 1 ) ) == APMBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'/proc/apm\'" ); + close( fd ); + return -1; + } + + close( fd ); + ApmBuf[ n ] = '\0'; + Dirty = 1; + + return 0; +} + +void printApmBatFill( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processApm(); + + fprintf( CurrentClient, "%d\n", BatFill ); +} + +void printApmBatFillInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Battery charge\t0\t100\t%%\n" ); +} + +void printApmBatTime( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processApm(); + + fprintf( CurrentClient, "%d\n", BatTime ); +} + +void printApmBatTimeInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Remaining battery time\t0\t0\tmin\n" ); +} diff --git a/ksysguard/ksysguardd/Linux/apm.h b/ksysguard/ksysguardd/Linux/apm.h new file mode 100644 index 000000000..982c77f7c --- /dev/null +++ b/ksysguard/ksysguardd/Linux/apm.h @@ -0,0 +1,34 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_APM_H +#define KSG_APM_H + +void initApm( struct SensorModul* ); +void exitApm( void ); + +int updateApm( void ); + +void printApmBatFill( const char* ); +void printApmBatFillInfo( const char* ); +void printApmBatTime( const char* ); +void printApmBatTimeInfo( const char* ); + +#endif diff --git a/ksysguard/ksysguardd/Linux/cpuinfo.c b/ksysguard/ksysguardd/Linux/cpuinfo.c new file mode 100644 index 000000000..de5deb80f --- /dev/null +++ b/ksysguard/ksysguardd/Linux/cpuinfo.c @@ -0,0 +1,179 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2000-2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <time.h> + +#include "Command.h" +#include "ksysguardd.h" + +#include "cpuinfo.h" + +static int CpuInfoOK = 0; +static float* Clocks = 0; +static int CPUs = 0; + +#define CPUINFOBUFSIZE (32 * 1024) +static char CpuInfoBuf[ CPUINFOBUFSIZE ]; +static int Dirty = 0; +static struct SensorModul *CpuInfoSM; + +static void processCpuInfo( void ) +{ + char format[ 32 ]; + char tag[ 32 ]; + char value[ 256 ]; + char* cibp = CpuInfoBuf; + int cpuId = 0; + + if ( !CpuInfoOK ) + return; + + sprintf( format, "%%%d[^:]: %%%d[^\n]\n", (int)sizeof( tag ) - 1, + (int)sizeof( value ) - 1 ); + + while ( sscanf( cibp, format, tag, value ) == 2 ) { + char* p; + tag[ sizeof( tag ) - 1 ] = '\0'; + value[ sizeof( value ) - 1 ] = '\0'; + /* remove trailing whitespaces */ + p = tag + strlen( tag ) - 1; + /* remove trailing whitespaces */ + while ( ( *p == ' ' || *p == '\t' ) && p > tag ) + *p-- = '\0'; + + if ( strcmp( tag, "processor" ) == 0 ) { + if ( sscanf( value, "%d", &cpuId ) == 1 ) { + if ( cpuId >= CPUs ) { + char cmdName[ 24 ]; + if ( Clocks ) + free( Clocks ); + CPUs = cpuId + 1; + Clocks = malloc( CPUs * sizeof( float ) ); + snprintf( cmdName, sizeof( cmdName ) - 1, "cpu%d/clock", cpuId ); + registerMonitor( cmdName, "float", printCPUxClock, printCPUxClockInfo, + CpuInfoSM ); + } + } + } else if ( strcmp( tag, "cpu MHz" ) == 0 ) + sscanf( value, "%f", &Clocks[ cpuId ] ); + + /* Move cibp to begining of next line, if there is one. */ + cibp = strchr( cibp, '\n' ); + if ( cibp ) + cibp++; + else + cibp = CpuInfoBuf + strlen( CpuInfoBuf ); + } + + Dirty = 0; +} + +/* +================================ public part ================================= +*/ + +void initCpuInfo( struct SensorModul* sm ) +{ + CpuInfoSM = sm; + + if ( updateCpuInfo() < 0 ) + return; + + processCpuInfo(); +} + +void exitCpuInfo( void ) +{ + CpuInfoOK = -1; + + free( Clocks ); +} + +int updateCpuInfo( void ) +{ + size_t n; + int fd; + + if ( CpuInfoOK < 0 ) + return -1; + + if ( ( fd = open( "/proc/cpuinfo", O_RDONLY ) ) < 0 ) { + if ( CpuInfoOK != 0 ) + print_error( "Cannot open file \'/proc/cpuinfo\'!\n" + "The kernel needs to be compiled with support\n" + "for /proc filesystem enabled!\n" ); + CpuInfoOK = -1; + return -1; + } + + n = 0; + for(;;) { + ssize_t len = read( fd, CpuInfoBuf + n, CPUINFOBUFSIZE - 1 - n ); + if( len < 0 ) { + print_error( "Failed to read file \'/proc/cpuinfo\'!\n" ); + CpuInfoOK = -1; + close( fd ); + return -1; + } + n += len; + if( len == 0 ) /* reading finished */ + break; + if( n == CPUINFOBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'/proc/cpuinfo\'" ); + CpuInfoOK = 0; + close( fd ); + return -1; + } + } + + close( fd ); + CpuInfoOK = 1; + CpuInfoBuf[ n ] = '\0'; + Dirty = 1; + + return 0; +} + +void printCPUxClock( const char* cmd ) +{ + int id; + + if ( Dirty ) + processCpuInfo(); + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "%f\n", Clocks[ id ] ); +} + +void printCPUxClockInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "CPU%d Clock Frequency\t0\t0\tMHz\n", id ); +} diff --git a/ksysguard/ksysguardd/Linux/cpuinfo.h b/ksysguard/ksysguardd/Linux/cpuinfo.h new file mode 100644 index 000000000..f2380cce7 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/cpuinfo.h @@ -0,0 +1,32 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2000-2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_CPUINFO_H +#define KSG_CPUINFO_H + +void initCpuInfo( struct SensorModul* ); +void exitCpuInfo( void ); + +int updateCpuInfo( void ); + +void printCPUxClock( const char* ); +void printCPUxClockInfo( const char* ); + +#endif diff --git a/ksysguard/ksysguardd/Linux/diskstat.c b/ksysguard/ksysguardd/Linux/diskstat.c new file mode 100644 index 000000000..012ed5a8e --- /dev/null +++ b/ksysguard/ksysguardd/Linux/diskstat.c @@ -0,0 +1,265 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <config.h> + +#include <mntent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/vfs.h> +#include <time.h> +#include <unistd.h> + +#include "Command.h" +#include "ccont.h" +#include "diskstat.h" +#include "ksysguardd.h" + +typedef struct { + char device[ 256 ]; + char mntpnt[ 256 ]; + long blocks; + long bfree; + long bused; + int bused_percent; +} DiskInfo; + +static CONTAINER DiskStatList = 0; +static struct SensorModul* DiskStatSM; +char *getMntPnt( const char* cmd ); + +char *getMntPnt( const char* cmd ) +{ + static char device[ 1025 ]; + char* ptr; + + memset( device, 0, sizeof( device ) ); + sscanf( cmd, "partitions%1024s", device ); + + ptr = (char*)rindex( device, '/' ); + *ptr = '\0'; + + return (char*)device; +} + +/* ----------------------------- public part ------------------------------- */ + +void initDiskStat( struct SensorModul* sm ) +{ + char monitor[ 1024 ]; + DiskInfo* disk_info; + + DiskStatList = new_ctnr(); + DiskStatSM = sm; + + if ( updateDiskStat() < 0 ) + return; + + registerMonitor( "partitions/list", "listview", printDiskStat, printDiskStatInfo, sm ); + + for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { + snprintf( monitor, sizeof( monitor ), "partitions%s/usedspace", disk_info->mntpnt ); + registerMonitor( monitor, "integer", printDiskStatUsed, printDiskStatUsedInfo, DiskStatSM ); + snprintf( monitor, sizeof( monitor ), "partitions%s/freespace", disk_info->mntpnt ); + registerMonitor( monitor, "integer", printDiskStatFree, printDiskStatFreeInfo, DiskStatSM ); + snprintf( monitor, sizeof( monitor ), "partitions%s/filllevel", disk_info->mntpnt ); + registerMonitor( monitor, "integer", printDiskStatPercent, printDiskStatPercentInfo, DiskStatSM ); + } +} + +void exitDiskStat( void ) +{ + char monitor[ 1024 ]; + DiskInfo* disk_info; + + removeMonitor( "partitions/list" ); + + for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { + snprintf( monitor, sizeof( monitor ), "partitions%s/usedspace", disk_info->mntpnt ); + removeMonitor( monitor ); + snprintf( monitor, sizeof( monitor ), "partitions%s/freespace", disk_info->mntpnt ); + removeMonitor( monitor ); + snprintf( monitor, sizeof( monitor ), "partitions%s/filllevel", disk_info->mntpnt ); + removeMonitor( monitor ); + } + + destr_ctnr( DiskStatList, free ); +} + +void checkDiskStat( void ) +{ + struct stat mtab_info; + static off_t mtab_size = 0; + + stat( "/etc/mtab", &mtab_info ); + if ( !mtab_size ) + mtab_size = mtab_info.st_size; + + if ( mtab_info.st_size != mtab_size ) { + exitDiskStat(); + initDiskStat( DiskStatSM ); + mtab_size = mtab_info.st_size; + } +} + +int updateDiskStat( void ) +{ + DiskInfo *disk_info; + FILE *fh; + struct mntent *mnt_info; + float percent; + int i; + struct statfs fs_info; + + if ( ( fh = setmntent( "/etc/mtab", "r" ) ) == NULL ) { + print_error( "Cannot open \'/etc/mtab\'!\n" ); + return -1; + } + + for ( i = level_ctnr( DiskStatList ); i >= 0; --i ) + free( pop_ctnr( DiskStatList ) ); + + while ( ( mnt_info = getmntent( fh ) ) != NULL ) { + if ( statfs( mnt_info->mnt_dir, &fs_info ) < 0 ) + continue; + + if ( strcmp( mnt_info->mnt_type, "proc" ) && + strcmp( mnt_info->mnt_type, "devfs" ) && + strcmp( mnt_info->mnt_type, "usbfs" ) && + strcmp( mnt_info->mnt_type, "sysfs" ) && + strcmp( mnt_info->mnt_type, "tmpfs" ) && + strcmp( mnt_info->mnt_type, "devpts" ) ) { + if ( fs_info.f_blocks != 0 ) + { + percent = ( ( (float)fs_info.f_blocks - (float)fs_info.f_bfree ) / + (float)fs_info.f_blocks ); + percent = percent * 100; + } + else + { + percent = 0; + } + + if ( ( disk_info = (DiskInfo *)malloc( sizeof( DiskInfo ) ) ) == NULL ) + continue; + + memset( disk_info, 0, sizeof( DiskInfo ) ); + strlcpy( disk_info->device, mnt_info->mnt_fsname, sizeof( disk_info->device ) ); + if ( !strcmp( mnt_info->mnt_dir, "/" ) ) + strlcpy( disk_info->mntpnt, "/root", sizeof( disk_info->mntpnt ) ); + else + strlcpy( disk_info->mntpnt, mnt_info->mnt_dir, sizeof( disk_info->mntpnt ) ); + + disk_info->blocks = fs_info.f_blocks; + disk_info->bfree = fs_info.f_bfree; + disk_info->bused = fs_info.f_blocks - fs_info.f_bfree; + disk_info->bused_percent = (int)percent; + + push_ctnr( DiskStatList, disk_info ); + } + } + + endmntent( fh ); + + return 0; +} + +void printDiskStat( const char* cmd ) +{ + DiskInfo* disk_info; + + (void)cmd; + for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { + fprintf( CurrentClient, "%s\t%ld\t%ld\t%ld\t%d\t%s\n", + disk_info->device, + disk_info->blocks, + disk_info->bused, + disk_info->bfree, + disk_info->bused_percent, + disk_info->mntpnt ); + } + + fprintf( CurrentClient, "\n" ); +} + +void printDiskStatInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Device\tBlocks\tUsed\tAvailable\tUsed %%\tMountPoint\nM\tD\tD\tD\td\ts\n" ); +} + +void printDiskStatUsed( const char* cmd ) +{ + char *mntpnt = (char*)getMntPnt( cmd ); + DiskInfo* disk_info; + + for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { + if ( !strcmp( mntpnt, disk_info->mntpnt ) ) + fprintf( CurrentClient, "%ld\n", disk_info->bused ); + } + + fprintf( CurrentClient, "\n" ); +} + +void printDiskStatUsedInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Used Blocks\t0\t-\tBlocks\n" ); +} + +void printDiskStatFree( const char* cmd ) +{ + char *mntpnt = (char*)getMntPnt( cmd ); + DiskInfo* disk_info; + + for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { + if ( !strcmp( mntpnt, disk_info->mntpnt ) ) + fprintf( CurrentClient, "%ld\n", disk_info->bfree ); + } + + fprintf( CurrentClient, "\n" ); +} + +void printDiskStatFreeInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Free Blocks\t0\t-\tBlocks\n" ); +} + +void printDiskStatPercent( const char* cmd ) +{ + char *mntpnt = (char*)getMntPnt( cmd ); + DiskInfo* disk_info; + + for ( disk_info = first_ctnr( DiskStatList ); disk_info; disk_info = next_ctnr( DiskStatList ) ) { + if ( !strcmp( mntpnt, disk_info->mntpnt ) ) + fprintf( CurrentClient, "%d\n", disk_info->bused_percent ); + } + + fprintf( CurrentClient, "\n" ); +} + +void printDiskStatPercentInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Used Blocks\t0\t100\t%%\n" ); +} diff --git a/ksysguard/ksysguardd/Linux/diskstat.h b/ksysguard/ksysguardd/Linux/diskstat.h new file mode 100644 index 000000000..6a23e6148 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/diskstat.h @@ -0,0 +1,40 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_DISKSTAT_H +#define KSG_DISKSTAT_H + +void initDiskStat( struct SensorModul* ); +void exitDiskStat( void ); + +int updateDiskStat( void ); +void checkDiskStat( void ); + +void printDiskStat( const char* ); +void printDiskStatInfo( const char* ); + +void printDiskStatUsed( const char* ); +void printDiskStatUsedInfo( const char* ); +void printDiskStatFree( const char* ); +void printDiskStatFreeInfo( const char* ); +void printDiskStatPercent( const char* ); +void printDiskStatPercentInfo( const char* ); + +#endif diff --git a/ksysguard/ksysguardd/Linux/i8k.c b/ksysguard/ksysguardd/Linux/i8k.c new file mode 100644 index 000000000..c6bbe7d72 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/i8k.c @@ -0,0 +1,150 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <fcntl.h> +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "Command.h" +#include "ksysguardd.h" + +#include "i8k.h" + +#ifdef HAVE_I8K_SUPPORT + +static int I8kOK = 0; +static int cpuTemp, fan0Speed, fan1Speed; + +#define I8KBUFSIZE 128 +static char I8kBuf[ I8KBUFSIZE ]; + +/* +================================ public part ================================= +*/ + +void initI8k( struct SensorModul* sm ) +{ + if ( updateI8k() < 0 ) { + I8kOK = -1; + return; + } else + I8kOK = 1; + + registerMonitor( "dell/cputemp", "integer", printI8kCPUTemperature, + printI8kCPUTemperatureInfo, sm ); + registerMonitor( "dell/fan0", "integer", printI8kFan0Speed, + printI8kFan0SpeedInfo, sm ); + registerMonitor( "dell/fan1", "integer", printI8kFan1Speed, + printI8kFan1SpeedInfo, sm ); +} + +void exitI8k( void ) +{ + I8kOK = -1; +} + +int updateI8k( void ) +{ + size_t n; + int fd; + + if ( I8kOK < 0 ) + return -1; + + if ( ( fd = open( "/proc/i8k", O_RDONLY ) ) < 0 ) { + print_error( "Cannot open file \'/proc/i8k\'!\n" + "The kernel needs to be compiled with support\n" + "for /proc filesystem enabled!\n" ); + return -1; + } + + if ( ( n = read( fd, I8kBuf, I8KBUFSIZE - 1 ) ) == I8KBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'/proc/i8k\'" ); + + close( fd ); + return -1; + } + + close( fd ); + I8kBuf[ n ] = '\0'; + + sscanf( I8kBuf, "%*f %*s %*s %d %*d %*d %d %d %*d %*d", + &cpuTemp, &fan0Speed, &fan1Speed ); + + return 0; +} + +void printI8kCPUTemperature( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "%d\n", cpuTemp ); +} + +void printI8kCPUTemperatureInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "CPU Temperature\t0\t0\tC\n" ); +} + +void printI8kFan0Speed( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "%d\n", fan0Speed ); +} + +void printI8kFan0SpeedInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Left fan\t0\t0\trpm\n" ); +} + +void printI8kFan1Speed( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "%d\n", fan1Speed ); +} + +void printI8kFan1SpeedInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Right fan\t0\t0\trpm\n" ); +} + +#else /* HAVE_I8K_SUPPORT */ + +/* dummy version for systems that have no i8k support */ + +void initI8k( struct SensorModul* sm ) +{ + (void)sm; +} + +void exitI8k( void ) +{ +} + +int updateI8k( void ) +{ + return 0; +} + +#endif diff --git a/ksysguard/ksysguardd/Linux/i8k.h b/ksysguard/ksysguardd/Linux/i8k.h new file mode 100644 index 000000000..40c2a886d --- /dev/null +++ b/ksysguard/ksysguardd/Linux/i8k.h @@ -0,0 +1,36 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_I8K_H +#define KSG_I8K_H + +void initI8k( struct SensorModul* ); +void exitI8k( void ); + +int updateI8k( void ); + +void printI8kCPUTemperature( const char* ); +void printI8kCPUTemperatureInfo( const char* ); +void printI8kFan0Speed( const char* ); +void printI8kFan0SpeedInfo( const char* ); +void printI8kFan1Speed( const char* ); +void printI8kFan1SpeedInfo( const char* ); + +#endif diff --git a/ksysguard/ksysguardd/Linux/lmsensors.c b/ksysguard/ksysguardd/Linux/lmsensors.c new file mode 100644 index 000000000..37e41d2a1 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/lmsensors.c @@ -0,0 +1,309 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "Command.h" +#include "ccont.h" +#include "ksysguardd.h" + +#include "lmsensors.h" + +#ifdef HAVE_SENSORS_SENSORS_H +#include <sensors/sensors.h> + +#ifndef SENSORS_API_VERSION +#define SENSORS_API_VERSION 0x000 +#endif +#ifndef SENSORS_CHIP_NAME_BUS_PCI +#define SENSORS_CHIP_NAME_BUS_PCI -5 +#endif +#ifndef SENSORS_CHIP_NAME_BUS_ISA +#define SENSORS_CHIP_NAME_BUS_ISA -1 +#endif + +#define BUFFER_SIZE_LMSEN 300 +typedef struct +{ + char* fullName; + const sensors_chip_name* scn; +#if SENSORS_API_VERSION & 0x400 + const sensors_feature *sf; + const sensors_subfeature *sfd; +#else + const sensors_feature_data* sfd; +#endif +} LMSENSOR; + +static CONTAINER LmSensors; +static int LmSensorsOk = -1; + +static int sensorCmp( void* s1, void* s2 ) +{ + return strcmp( ((LMSENSOR*)s1)->fullName, ((LMSENSOR*)s2)->fullName ); +} + +static LMSENSOR* findMatchingSensor( const char* name ) +{ + INDEX idx; + LMSENSOR key; + LMSENSOR* s; + + if(name == NULL || name[0] == '\0') return 0; + key.fullName = strdup( name ); + int end = strlen(key.fullName)-1; + if(key.fullName[end] == '?') + key.fullName[end] = '\0'; + if ( ( idx = search_ctnr( LmSensors, sensorCmp, &key ) ) < 0 ) { + free( key.fullName ); + return 0; + } + + free( key.fullName ); + s = get_ctnr( LmSensors, idx ); + + return s; +} + +static const char *chipName(const sensors_chip_name *chip) { + static char buffer[256]; +#if SENSORS_API_VERSION & 0x400 + sensors_snprintf_chip_name(buffer, sizeof(buffer), chip); +#else /* SENSORS_API_VERSION & 0x400 */ + if (chip->bus == SENSORS_CHIP_NAME_BUS_ISA) + snprintf (buffer, sizeof(buffer), "%s-isa-%04x", chip->prefix, chip->addr); + else if (chip->bus == SENSORS_CHIP_NAME_BUS_PCI) + snprintf (buffer, sizeof(buffer), "%s-pci-%04x", chip->prefix, chip->addr); + else + snprintf (buffer, sizeof(buffer), "%s-i2c-%d-%02x", chip->prefix, chip->bus, chip->addr); +#endif /* SENSORS_API_VERSION & 0x400 */ + return buffer; +} + +#if SENSORS_API_VERSION & 0x400 +void initLmSensors( struct SensorModul* sm ) +{ + const sensors_chip_name* scn; + int nr = 0; + + if ( sensors_init( NULL ) ) { + LmSensorsOk = -1; + return; + } + + LmSensors = new_ctnr(); + while ( ( scn = sensors_get_detected_chips( NULL, &nr ) ) != NULL ) { + int nr1 = 0; + const sensors_feature* sf; + + while ( ( sf = sensors_get_features( scn, &nr1 ) ) != 0 ) { + const sensors_subfeature *ssubf; + LMSENSOR *p; + char *s, *label; + + switch( sf->type ) + { + case SENSORS_FEATURE_IN: + ssubf = sensors_get_subfeature( scn, sf, + SENSORS_SUBFEATURE_IN_INPUT ); + break; + + case SENSORS_FEATURE_FAN: + ssubf = sensors_get_subfeature( scn, sf, + SENSORS_SUBFEATURE_FAN_INPUT ); + break; + + case SENSORS_FEATURE_TEMP: + ssubf = sensors_get_subfeature( scn, sf, + SENSORS_SUBFEATURE_TEMP_INPUT ); + break; + default: + ssubf = NULL; + } + + if ( !ssubf ) + continue; + + label = sensors_get_label( scn, sf ); + p = (LMSENSOR*)malloc( sizeof( LMSENSOR ) ); + p->fullName = (char*)malloc( strlen( "lmsensors/" ) + + strlen( scn->prefix ) + 1 + + strlen( label ) + 1 ); + snprintf( p->fullName, BUFFER_SIZE_LMSEN, "lmsensors/%s/%s", scn->prefix, label ); + + /* Make sure that name contains only proper characters. */ + for ( s = p->fullName; *s; s++ ) + if ( *s == ' ' ) + *s = '_'; + + p->scn = scn; + p->sf = sf; + p->sfd = ssubf; + + /* Note a name collision should never happen with the lm_sensors-3x code, + but it does in the case of k8temp, when there are 2 identical labeled + sensors per CPU. This are really 2 distinct sensors measuring the + same thing, but fullName must be unique so we just drop the second + sensor */ + if ( search_ctnr( LmSensors, sensorCmp, p ) < 0 ) { + push_ctnr( LmSensors, p ); + registerMonitor( p->fullName, "float", printLmSensor, printLmSensorInfo, sm ); + } else { + free( p->fullName ); + free( p ); + } + free( label ); + } + } + bsort_ctnr( LmSensors, sensorCmp ); +} +#else /* SENSORS_API_VERSION & 0x400 */ +void initLmSensors( struct SensorModul* sm ) +{ + const sensors_chip_name* scn; + char buffer[BUFFER_SIZE_LMSEN]; + int nr = 0; + + FILE* input; + if ( ( input = fopen( "/etc/sensors.conf", "r" ) ) == NULL ) { + LmSensorsOk = -1; + return; + } + + if ( sensors_init( input ) ) { + LmSensorsOk = -1; + fclose( input ); + return; + } + + fclose( input ); + + LmSensors = new_ctnr(); + while ( ( scn = sensors_get_detected_chips( &nr ) ) != NULL ) { + int nr1, nr2; + const sensors_feature_data* sfd; + nr1 = nr2 = 0; + while ( ( sfd = sensors_get_all_features( *scn, &nr1, &nr2 ) ) != 0 ) { + if ( sfd->mapping == SENSORS_NO_MAPPING && sfd->mode & SENSORS_MODE_R /* readable feature */) { + LMSENSOR* p; + char* label=NULL; + + if(sensors_get_label( *scn, sfd->number, &label ) != 0) + continue; /*error*/ + else + free( label ); + if(sensors_get_ignored( *scn, sfd->number) != 1 ) + continue; /* 1 for not ignored, 0 for ignore, <0 for error */ + double result; + if(sensors_get_feature( *scn, sfd->number, &result) != 0 ) + continue; /* Make sure this feature actually works. 0 for success, <0 for fail */ + + p = (LMSENSOR*)malloc( sizeof( LMSENSOR ) ); + + snprintf( buffer, BUFFER_SIZE_LMSEN, "lmsensors/%s/%s", chipName(scn), sfd->name ); + + p->fullName = strndup(buffer, BUFFER_SIZE_LMSEN); + + p->scn = scn; + p->sfd = sfd; + if ( search_ctnr( LmSensors, sensorCmp, p ) < 0 ) { + push_ctnr( LmSensors, p ); + registerMonitor( p->fullName, "float", printLmSensor, printLmSensorInfo, sm ); + } else { + free( p->fullName ); + free( p ); + } + } + } + } + bsort_ctnr( LmSensors, sensorCmp ); +} +#endif /* SENSORS_API_VERSION & 0x400 */ + +void exitLmSensors( void ) +{ + destr_ctnr( LmSensors, free ); +} + +void printLmSensor( const char* cmd ) +{ + double value; + LMSENSOR* s; + + if ( ( s = findMatchingSensor( cmd ) ) == 0 ) { /* should never happen */ + fprintf( CurrentClient, "0\n" ); + return; + } +#if SENSORS_API_VERSION & 0x400 + sensors_get_value( s->scn, s->sfd->number, &value ); +#else + sensors_get_feature( *(s->scn), s->sfd->number, &value ); +#endif + fprintf( CurrentClient, "%f\n", value ); +} + +void printLmSensorInfo( const char* cmd ) +{ + LMSENSOR* s; + + if ( ( s = findMatchingSensor( cmd ) ) == 0 ) { /* should never happen */ + fprintf( CurrentClient, "0\n" ); + return; + } + + /* TODO: print real name here */ + char *label; +#if SENSORS_API_VERSION & 0x400 + label = sensors_get_label( s->scn, s->sf ); + if (label == NULL) { +#else + if(sensors_get_label( *s->scn, s->sfd->number, &label ) != 0) { /*error*/ +#endif + fprintf( CurrentClient, "0\n" ); + return; + } + if( strncmp(s->sfd->name, "temp", sizeof("temp")-1) == 0) + fprintf( CurrentClient, "%s\t0\t0\t°C\n", label ); + else if( strncmp(s->sfd->name, "fan", sizeof("fan")-1) == 0) + fprintf( CurrentClient, "%s\t0\t0\trpm\n", label ); + else + fprintf( CurrentClient, "%s\t0\t0\tV\n", label ); /* For everything else, say it's in volts. */ +#if SENSORS_API_VERSION & 0x400 + free(label); +#endif +} + +#else /* HAVE_SENSORS_SENSORS_H */ + +/* dummy version for systems that have no lmsensors support */ + +void initLmSensors( struct SensorModul* sm ) +{ + (void)sm; +} + +void exitLmSensors( void ) +{ +} + +#endif diff --git a/ksysguard/ksysguardd/Linux/lmsensors.h b/ksysguard/ksysguardd/Linux/lmsensors.h new file mode 100644 index 000000000..29f514d4a --- /dev/null +++ b/ksysguard/ksysguardd/Linux/lmsensors.h @@ -0,0 +1,30 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_LMSENSORS_H +#define KSG_LMSENSORS_H + +void initLmSensors( struct SensorModul* ); +void exitLmSensors( void ); + +void printLmSensor( const char* ); +void printLmSensorInfo( const char* ); + +#endif diff --git a/ksysguard/ksysguardd/Linux/loadavg.c b/ksysguard/ksysguardd/Linux/loadavg.c new file mode 100644 index 000000000..788e32793 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/loadavg.c @@ -0,0 +1,143 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> + +#include "ksysguardd.h" +#include "Command.h" + +#include "loadavg.h" + +static int LoadAvgOK = 0; +static double LoadAvg1, LoadAvg5, LoadAvg15; + +#define LOADAVGBUFSIZE 128 +static char LoadAvgBuf[ LOADAVGBUFSIZE ]; +static int Dirty = 0; + +static void processLoadAvg( void ) +{ + sscanf( LoadAvgBuf, "%lf %lf %lf", &LoadAvg1, &LoadAvg5, &LoadAvg15 ); + Dirty = 0; +} + +/* +================================ public part ================================= +*/ + +void initLoadAvg( struct SensorModul* sm ) +{ + if ( updateLoadAvg() < 0 ) { + LoadAvgOK = -1; + return; + } else + LoadAvgOK = 1; + + registerMonitor( "cpu/loadavg1", "float", printLoadAvg1, printLoadAvg1Info, sm ); + registerMonitor( "cpu/loadavg5", "float", printLoadAvg5, printLoadAvg5Info, sm ); + registerMonitor( "cpu/loadavg15", "float", printLoadAvg15, printLoadAvg15Info, sm ); +} + +void exitLoadAvg( void ) +{ + LoadAvgOK = -1; +} + +int updateLoadAvg( void ) +{ + size_t n; + int fd; + + if ( LoadAvgOK < 0 ) + return -1; + + if ( ( fd = open( "/proc/loadavg", O_RDONLY ) ) < 0 ) { + if ( LoadAvgOK != 0 ) + print_error( "Cannot open file \'/proc/loadavg\'!\n" + "The kernel needs to be compiled with support\n" + "for /proc filesystem enabled!\n" ); + return -1; + } + + if ( ( n = read( fd, LoadAvgBuf, LOADAVGBUFSIZE - 1 ) ) == LOADAVGBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'/proc/loadavg\'" ); + + close( fd ); + return -1; + } + + close( fd ); + LoadAvgBuf[ n ] = '\0'; + Dirty = 1; + + return 0; +} + +void printLoadAvg1( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processLoadAvg(); + + fprintf( CurrentClient, "%f\n", LoadAvg1 ); +} + +void printLoadAvg1Info( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Load average 1 min\t0\t0\t\n" ); +} + +void printLoadAvg5( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processLoadAvg(); + + fprintf( CurrentClient, "%f\n", LoadAvg5 ); +} + +void printLoadAvg5Info( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Load average 5 min\t0\t0\t\n" ); +} + +void printLoadAvg15( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processLoadAvg(); + + fprintf( CurrentClient, "%f\n", LoadAvg15 ); +} + +void printLoadAvg15Info( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Load average 15 min\t0\t0\t\n" ); +} diff --git a/ksysguard/ksysguardd/Linux/loadavg.h b/ksysguard/ksysguardd/Linux/loadavg.h new file mode 100644 index 000000000..31628ac96 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/loadavg.h @@ -0,0 +1,36 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_LOADAVG_H +#define KSG_LOADAVG_H + +void initLoadAvg( struct SensorModul* ); +void exitLoadAvg( void ); + +int updateLoadAvg( void ); + +void printLoadAvg1( const char* ); +void printLoadAvg1Info( const char* ); +void printLoadAvg5( const char* ); +void printLoadAvg5Info( const char* ); +void printLoadAvg15( const char* ); +void printLoadAvg15Info( const char* ); + +#endif diff --git a/ksysguard/ksysguardd/Linux/logfile.c b/ksysguard/ksysguardd/Linux/logfile.c new file mode 100644 index 000000000..58915a207 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/logfile.c @@ -0,0 +1,172 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "Command.h" +#include "ccont.h" +#include "conf.h" +#include "ksysguardd.h" + +#include "logfile.h" + +static CONTAINER LogFiles = 0; +static unsigned long counter = 1; + +typedef struct { + char name[ 256 ]; + FILE* fh; + unsigned long id; +} LogFileEntry; + +extern CONTAINER LogFileList; + +/* +================================ public part ================================= +*/ + +void initLogFile( struct SensorModul* sm ) +{ + char monitor[ 1024 ]; + ConfigLogFile *entry; + + registerCommand( "logfile_register", registerLogFile ); + registerCommand( "logfile_unregister", unregisterLogFile ); + registerCommand( "logfile_registered", printRegistered ); + + for ( entry = first_ctnr( LogFileList ); entry; entry = next_ctnr( LogFileList ) ) { + FILE* fp; + /* Register the log file only if we can actually read the file. */ + if ( ( fp = fopen( entry->path, "r" ) ) != NULL ) { + snprintf( monitor, 1024, "logfiles/%s", entry->name ); + registerMonitor( monitor, "logfile", printLogFile, printLogFileInfo, sm ); + fclose( fp ); + } + } + + LogFiles = new_ctnr(); +} + +void exitLogFile( void ) +{ + destr_ctnr( LogFiles, free ); +} + +void printLogFile( const char* cmd ) +{ + char line[ 1024 ]; + unsigned long id; + LogFileEntry *entry; + + sscanf( cmd, "%*s %lu", &id ); + + for ( entry = first_ctnr( LogFiles ); entry; entry = next_ctnr( LogFiles ) ) { + if ( entry->id == id ) { + while ( fgets( line, 1024, entry->fh ) != NULL ) + fprintf( CurrentClient, "%s", line ); + + /* delete the EOF */ + clearerr( entry->fh ); + } + } + + fprintf( CurrentClient, "\n" ); +} + +void printLogFileInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "LogFile\n" ); +} + +void registerLogFile( const char* cmd ) +{ + char name[ 257 ]; + FILE* file; + LogFileEntry *entry; + int i; + + memset( name, 0, sizeof( name ) ); + sscanf( cmd, "%*s %256s", name ); + + for ( i = 0; i < level_ctnr( LogFileList ); i++ ) { + ConfigLogFile *conf = get_ctnr( LogFileList, i ); + if ( !strcmp( conf->name, name ) ) { + if ( ( file = fopen( conf->path, "r" ) ) == NULL ) { + print_error( "fopen()" ); + fprintf( CurrentClient, "0\n" ); + return; + } + + fseek( file, 0, SEEK_END ); + + if ( ( entry = (LogFileEntry*)malloc( sizeof( LogFileEntry ) ) ) == NULL ) { + print_error( "malloc()" ); + fprintf( CurrentClient, "0\n" ); + return; + } + + entry->fh = file; + strncpy( entry->name, conf->name, 256 ); + entry->id = counter; + + push_ctnr( LogFiles, entry ); + + fprintf( CurrentClient, "%lu\n", counter ); + counter++; + + return; + } + } + + fprintf( CurrentClient, "\n" ); +} + +void unregisterLogFile( const char* cmd ) +{ + unsigned long id; + LogFileEntry *entry; + + sscanf( cmd, "%*s %lu", &id ); + + for ( entry = first_ctnr( LogFiles ); entry; entry = next_ctnr( LogFiles ) ) { + if ( entry->id == id ) { + fclose( entry->fh ); + free( remove_ctnr( LogFiles ) ); + fprintf( CurrentClient, "\n" ); + return; + } + } + + fprintf( CurrentClient, "\n" ); +} + +void printRegistered( const char* cmd ) +{ + LogFileEntry *entry; + + (void)cmd; + for ( entry = first_ctnr( LogFiles ); entry; entry = next_ctnr( LogFiles ) ) + fprintf( CurrentClient, "%s:%lu\n", entry->name, entry->id ); + + fprintf( CurrentClient, "\n" ); +} diff --git a/ksysguard/ksysguardd/Linux/logfile.h b/ksysguard/ksysguardd/Linux/logfile.h new file mode 100644 index 000000000..5eecb2f70 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/logfile.h @@ -0,0 +1,36 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_LOGFILE_H +#define KSG_LOGFILE_H + +void initLogFile( struct SensorModul* ); +void exitLogFile( void ); + +void printLogFile( const char* ); +void printLogFileInfo( const char* ); + +void registerLogFile( const char* ); +void unregisterLogFile( const char* ); + +/* debug command */ +void printRegistered( const char* ); + +#endif diff --git a/ksysguard/ksysguardd/Linux/netdev.c b/ksysguard/ksysguardd/Linux/netdev.c new file mode 100644 index 000000000..55e812807 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/netdev.c @@ -0,0 +1,367 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <config.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> + +#include "Command.h" +#include "ksysguardd.h" + +#include "netdev.h" + +#define MON_SIZE 128 + +#define CALC( a, b, c, d, e ) \ +{ \ + NetDevs[ i ].a = a - NetDevs[ i ].Old##a; \ + NetDevs[ i ].Old##a = a; \ +} + +#define REGISTERSENSOR( a, b, c, d, e ) \ +{ \ + snprintf( mon, MON_SIZE, "network/interfaces/%s/%s", tag, b ); \ + registerMonitor( mon, "integer", printNetDev##a, printNetDev##a##Info, NetDevSM ); \ +} + +#define UNREGISTERSENSOR( a, b, c, d, e ) \ +{ \ + snprintf( mon, MON_SIZE, "network/interfaces/%s/%s", NetDevs[ i ].name, b ); \ + removeMonitor( mon ); \ +} + +#define DEFMEMBERS( a, b, c, d, e ) \ +unsigned long long Old##a; \ +unsigned long long a; \ +unsigned long a##Scale; + +#define DEFVARS( a, b, c, d, e ) \ +unsigned long long a; + +#define FORALL( a ) \ + a( recBytes, "receiver/data", "Received Data", "kBytes/s", 1024 ) \ + a( recPacks, "receiver/packets", "Received Packets", "1/s", 1 ) \ + a( recErrs, "receiver/errors", "Receiver Errors", "1/s", 1 ) \ + a( recDrop, "receiver/drops", "Receiver Drops", "1/s", 1 ) \ + a( recFifo, "receiver/fifo", "Receiver FIFO Overruns", "1/s", 1 ) \ + a( recFrame, "receiver/frame", "Receiver Frame Errors", "1/s", 1 ) \ + a( recCompressed, "receiver/compressed", "Received Compressed Packets", "1/s", 1 ) \ + a( recMulticast, "receiver/multicast", "Received Multicast Packets", "1/s", 1 ) \ + a( sentBytes, "transmitter/data", "Sent Data", "kBytes/s", 1024 ) \ + a( sentPacks, "transmitter/packets", "Sent Packets", "1/s", 1 ) \ + a( sentErrs, "transmitter/errors", "Transmitter Errors", "1/s", 1 ) \ + a( sentDrop, "transmitter/drops", "Transmitter Drops", "1/s", 1 ) \ + a( sentFifo, "transmitter/fifo", "Transmitter FIFO overruns", "1/s", 1 ) \ + a( sentColls, "transmitter/collisions", "Transmitter Collisions", "1/s", 1 ) \ + a( sentCarrier, "transmitter/carrier", "Transmitter Carrier losses", "1/s", 1 ) \ + a( sentCompressed, "transmitter/compressed", "Transmitter Compressed Packets", "1/s", 1 ) + +#define SETZERO( a, b, c, d, e ) \ +a = 0; + +#define SETMEMBERZERO( a, b, c, d, e ) \ +NetDevs[ i ].a = 0; \ +NetDevs[ i ].a##Scale = e; + +#define DECLAREFUNC( a, b, c, d, e ) \ +void printNetDev##a( const char* cmd ); \ +void printNetDev##a##Info( const char* cmd ); + +typedef struct +{ + FORALL( DEFMEMBERS ) + char name[ 32 ]; +} NetDevInfo; + +/* We have observed deviations of up to 5% in the accuracy of the timer + * interrupts. So we try to measure the interrupt interval and use this + * value to calculate timing dependant values. */ +static float timeInterval = 0; +static struct timeval lastSampling; +static struct timeval currSampling; +static struct SensorModul* NetDevSM; + +#define NETDEVBUFSIZE 4096 +static char NetDevBuf[ NETDEVBUFSIZE ]; +static int NetDevCnt = 0; +static int Dirty = 0; +static int NetDevOk = 0; +static long OldHash = 0; + +#define MAXNETDEVS 64 +static NetDevInfo NetDevs[ MAXNETDEVS ]; + +void processNetDev( void ); + +FORALL( DECLAREFUNC ) + +static int processNetDev_( void ) +{ + int i; + char format[ 32 ]; + char devFormat[ 16 ]; + char buf[ 1024 ]; + char tag[ 64 ]; + char* netDevBufP = NetDevBuf; + + sprintf( format, "%%%d[^\n]\n", (int)sizeof( buf ) - 1 ); + sprintf( devFormat, "%%%ds", (int)sizeof( tag ) - 1 ); + + /* skip 2 first lines */ + for ( i = 0; i < 2; i++ ) { + sscanf( netDevBufP, format, buf ); + buf[ sizeof( buf ) - 1 ] = '\0'; + netDevBufP += strlen( buf ) + 1; /* move netDevBufP to next line */ + } + + for ( i = 0; sscanf( netDevBufP, format, buf ) == 1; ++i ) { + buf[ sizeof( buf ) - 1 ] = '\0'; + netDevBufP += strlen( buf ) + 1; /* move netDevBufP to next line */ + + if ( sscanf( buf, devFormat, tag ) ) { + char* pos = strchr( tag, ':' ); + if ( pos ) { + FORALL( DEFVARS ); + *pos = '\0'; + FORALL( SETZERO ); + sscanf( buf + 7, "%llu %llu %llu %llu %llu %llu %llu %llu " + "%llu %llu %llu %llu %llu %llu %llu %llu", + &recBytes, &recPacks, &recErrs, &recDrop, &recFifo, + &recFrame, &recCompressed, &recMulticast, + &sentBytes, &sentPacks, &sentErrs, &sentDrop, + &sentFifo, &sentColls, &sentCarrier, &sentCompressed ); + + if ( i >= NetDevCnt || strcmp( NetDevs[ i ].name, tag ) != 0 ) { + /* The network device configuration has changed. We + * need to reconfigure the netdev module. */ + return -1; + } else { + FORALL( CALC ); + } + } + } + } + + if ( i != NetDevCnt ) + return -1; + + /* save exact time inverval between this and the last read of + * /proc/net/dev */ + timeInterval = currSampling.tv_sec - lastSampling.tv_sec + + ( currSampling.tv_usec - lastSampling.tv_usec ) / 1000000.0; + lastSampling = currSampling; + Dirty = 0; + + return 0; +} + +void processNetDev( void ) +{ + int i; + + if ( NetDevCnt == 0 ) + return; + + for ( i = 0; i < 5 && processNetDev_() < 0; ++i ) + checkNetDev(); + + /* If 5 reconfiguration attemts failed, something is very wrong and + * we close the netdev module for further use. */ + if ( i == 5 ) + exitNetDev(); +} + +/* +================================ public part ================================= +*/ + +void initNetDev( struct SensorModul* sm ) +{ + int i; + char format[ 32 ]; + char devFormat[ 16 ]; + char buf[ 1024 ]; + char tag[ 64 ]; + char* netDevBufP = NetDevBuf; + + NetDevSM = sm; + + if ( updateNetDev() < 0 ) + return; + + sprintf( format, "%%%d[^\n]\n", (int)sizeof( buf ) - 1 ); + sprintf( devFormat, "%%%ds", (int)sizeof( tag ) - 1 ); + + /* skip 2 first lines */ + for ( i = 0; i < 2; i++ ) { + sscanf( netDevBufP, format, buf ); + buf[ sizeof( buf ) - 1 ] = '\0'; + netDevBufP += strlen( buf ) + 1; /* move netDevBufP to next line */ + } + + for ( i = 0; sscanf( netDevBufP, format, buf ) == 1; ++i ) { + buf[ sizeof( buf ) - 1 ] = '\0'; + netDevBufP += strlen( buf ) + 1; /* move netDevBufP to next line */ + + if ( sscanf( buf, devFormat, tag ) ) { + char* pos = strchr( tag, ':' ); + if ( pos ) { + char mon[ MON_SIZE ]; + *pos = '\0'; + strlcpy( NetDevs[ i ].name, tag, sizeof( NetDevs[ i ].name ) ); + FORALL( REGISTERSENSOR ); + sscanf( pos + 1, "%llu %llu %llu %llu %llu %llu %llu %llu" + "%llu %llu %llu %llu %llu %llu %llu %llu", + &NetDevs[ i ].recBytes, &NetDevs[ i ].recPacks, + &NetDevs[ i ].recErrs, &NetDevs[ i ].recDrop, + &NetDevs[ i ].recFifo, &NetDevs[ i ].recFrame, + &NetDevs[ i ].recCompressed, &NetDevs[ i ].recMulticast, + &NetDevs[ i ].sentBytes, &NetDevs[ i ].sentPacks, + &NetDevs[ i ].sentErrs, &NetDevs[ i ].sentDrop, + &NetDevs[ i ].sentFifo, &NetDevs[ i ].sentColls, + &NetDevs[ i ].sentCarrier, &NetDevs[ i ].sentCompressed ); + NetDevCnt++; + } + FORALL( SETMEMBERZERO ); + } + } + + /* Call processNetDev to elimitate initial peek values. */ + processNetDev(); +} + +void exitNetDev( void ) +{ + int i; + + for ( i = 0; i < NetDevCnt; ++i ) { + char mon[ MON_SIZE ]; + FORALL( UNREGISTERSENSOR ); + } + NetDevCnt = 0; +} + +int updateNetDev( void ) +{ + /* We read the information about the network interfaces from + /proc/net/dev. The file should look like this: + + Inter-| Receive | Transmit + face | bytes packets errs drop fifo frame compressed multicast| bytes packets errs drop fifo colls carrier compressed + lo:275135772 1437448 0 0 0 0 0 0 275135772 1437448 0 0 0 0 0 0 + eth0:123648812 655251 0 0 0 0 0 0 246847871 889636 0 0 0 0 0 0 Inter-| Receive | Transmit + face | bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed + lo:275135772 1437448 0 0 0 0 0 0 275135772 1437448 0 0 0 0 0 0 + eth0:123648812 655251 0 0 0 0 0 0 246847871 889636 0 0 0 0 0 0 + */ + + size_t n; + int fd; + long hash; + char* p; + + if ( NetDevOk < 0 ) + return 0; + + if ( ( fd = open( "/proc/net/dev", O_RDONLY ) ) < 0 ) { + /* /proc/net/dev may not exist on some machines. */ + NetDevOk = -1; + return 0; + } + + if ( ( n = read( fd, NetDevBuf, NETDEVBUFSIZE - 1 ) ) == NETDEVBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'/proc/net/dev\'" ); + NetDevOk = -1; + + close( fd ); + return -1; + } + + gettimeofday( &currSampling, 0 ); + close( fd ); + NetDevOk = 1; + NetDevBuf[ n ] = '\0'; + + /* Calculate hash over the first 7 characters of each line starting + * after the first newline. */ + for ( p = NetDevBuf, hash = 0; *p; ++p ) + if ( *p == '\n' ) + for ( ++p; *p && *p != ':' && *p != '|'; ++p ) + hash = ( ( hash << 6 ) + *p ) % 390389; + + if ( OldHash != 0 && OldHash != hash ) { + print_error( "RECONFIGURE\n" ); + CheckSetupFlag = 1; + } + OldHash = hash; + + Dirty = 1; + + return 0; +} + +void checkNetDev( void ) +{ + /* Values for other network devices are lost, but it is still better + * than not detecting any new devices. TODO: Fix after 2.1 is out. */ + exitNetDev(); + initNetDev( NetDevSM ); +} + +#define PRINTFUNC( a, b, c, d, e ) \ +void printNetDev##a( const char* cmd ) \ +{ \ + int i; \ + char* beg; \ + char* end; \ + char dev[ 64 ]; \ + \ + beg = strchr( cmd, '/' ); \ + beg = strchr( beg + 1, '/' ); \ + end = strchr( beg + 1, '/' ); \ + strncpy( dev, beg + 1, end - beg - 1 ); \ + dev[ end - beg - 1 ] = '\0'; \ + \ + if ( Dirty ) \ + processNetDev(); \ + \ + for ( i = 0; i < MAXNETDEVS; ++i ) \ + if ( strcmp( NetDevs[ i ].name, dev ) == 0) { \ + fprintf( CurrentClient, "%lu\n", (unsigned long) \ + ( NetDevs[ i ].a / ( NetDevs[ i ].a##Scale * timeInterval ) ) ); \ + return; \ + } \ + \ + fprintf( CurrentClient, "0\n" ); \ +} \ + \ +void printNetDev##a##Info( const char* cmd ) \ +{ \ + (void)cmd; \ + fprintf( CurrentClient, "%s\t0\t0\t%s\n", c, d ); \ +} + +FORALL( PRINTFUNC ) diff --git a/ksysguard/ksysguardd/Linux/netdev.h b/ksysguard/ksysguardd/Linux/netdev.h new file mode 100644 index 000000000..d470adfae --- /dev/null +++ b/ksysguard/ksysguardd/Linux/netdev.h @@ -0,0 +1,35 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_NETDEV_H +#define KSG_NETDEV_H + +void initNetDev( struct SensorModul* ); +void exitNetDev( void ); + +int updateNetDev( void ); +void checkNetDev( void ); + +void printNetDevRecBytes( const char* ); +void printNetDevRecBytesInfo( const char* ); +void printNetDevSentBytes( const char* ); +void printNetDevSentBytesInfo( const char* ); + +#endif diff --git a/ksysguard/ksysguardd/Linux/netstat.c b/ksysguard/ksysguardd/Linux/netstat.c new file mode 100644 index 000000000..c8570f617 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/netstat.c @@ -0,0 +1,495 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <config.h> + +#include <arpa/inet.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "ksysguardd.h" +#include "Command.h" +#include "ccont.h" +#include "netstat.h" + +static CONTAINER TcpSocketList = 0; +static CONTAINER UdpSocketList = 0; +static CONTAINER UnixSocketList = 0; +static CONTAINER RawSocketList = 0; + +static int num_tcp = 0; +static int num_udp = 0; +static int num_unix = 0; +static int num_raw = 0; + +typedef struct { + char local_addr[128]; + char local_port[128]; + char remote_addr[128]; + char remote_port[128]; + char state[128]; + int uid; +} SocketInfo; + +typedef struct { + int refcount; + char type[128]; + char state[128]; + int inode; + char path[256]; +} UnixInfo; + +char *get_serv_name(int port, const char *proto); +char *get_host_name(int addr); +char *get_proto_name(int number); +int get_num_sockets(FILE *netstat); +void printSocketInfo(SocketInfo* socket_info); + +static time_t TcpUdpRaw_timeStamp = 0; +static time_t Unix_timeStamp = 0; +static time_t NetStat_timeStamp = 0; + +static const char *raw_type[] = +{ + "", + "stream", + "dgram", + "raw", + "rdm", + "seqpacket", + "packet" +}; + +static const char *raw_state[] = +{ + "free", + "unconnected", + "connecting", + "connected", + "disconnecting" +}; + +static const char *conn_state[] = +{ + "", + "established", + "syn_sent", + "syn_recv", + "fin_wait1", + "fin_wait2", + "time_wait", + "close", + "close_wait", + "last_ack", + "listen", + "closing" +}; + +char *get_serv_name(int port, const char *proto) +{ + static char buffer[1024]; + struct servent *service; + + if (port == 0) { + return (char *)"*"; + } + + memset(buffer, 0, sizeof(buffer)); + + if ((service = getservbyport(ntohs(port), proto)) == NULL) { + snprintf(buffer, sizeof(buffer), "%d", port); + } else { + strlcpy(buffer, service->s_name, sizeof(buffer)); + } + + return (char *)buffer; +} + +char *get_host_name(int addr) +{ + static char buffer[1024]; + struct hostent *host; + struct in_addr a_addr; + + if (addr == 0) { + return (char *)"*"; + } + + memset(buffer, 0, sizeof(buffer)); + + if ((host = gethostbyaddr((char *)&addr, 4, AF_INET)) == NULL) { + a_addr.s_addr = addr; + return inet_ntoa(a_addr); + } else { + strlcpy(buffer, host->h_name, sizeof(buffer)); + return (char *)buffer; + } +} + +char *get_proto_name(int number) +{ + static char buffer[1024]; + struct protoent *protocol; + + if (number == 0) { + return (char *)"*"; + } + + memset(buffer, 0, sizeof(buffer)); + + if ((protocol = getprotobynumber(number)) == NULL) { + snprintf(buffer, sizeof(buffer), "%d", number); + } else { + strlcpy(buffer, protocol->p_name, sizeof(buffer)); + } + + return (char *)buffer; +} + +int get_num_sockets(FILE *netstat) +{ + char line[1024]; + int line_count = 0; + + while (fgets(line, 1024, netstat) != NULL) + line_count++; + + return line_count - 1; +} + +void printSocketInfo(SocketInfo* socket_info) +{ + fprintf(CurrentClient, "%s\t%s\t%s\t%s\t%s\t%d\n", + socket_info->local_addr, + socket_info->local_port, + socket_info->remote_addr, + socket_info->remote_port, + socket_info->state, + socket_info->uid); +} + +/* +================================ public part ================================= +*/ + +void +initNetStat(struct SensorModul* sm) +{ + FILE *netstat; + + if ((netstat = fopen("/proc/net/tcp", "r")) != NULL) { + registerMonitor("network/sockets/tcp/count", "integer", printNetStat, printNetStatInfo, sm); + registerMonitor("network/sockets/tcp/list", "listview", printNetStatTcpUdpRaw, printNetStatTcpUdpRawInfo, sm); + fclose(netstat); + } + if ((netstat = fopen("/proc/net/udp", "r")) != NULL) { + registerMonitor("network/sockets/udp/count", "integer", printNetStat, printNetStatInfo, sm); + registerMonitor("network/sockets/udp/list", "listview", printNetStatTcpUdpRaw, printNetStatTcpUdpRawInfo, sm); + fclose(netstat); + } + if ((netstat = fopen("/proc/net/unix", "r")) != NULL) { + registerMonitor("network/sockets/unix/count", "integer", printNetStat, printNetStatInfo, sm); + registerMonitor("network/sockets/unix/list", "listview", printNetStatUnix, printNetStatUnixInfo, sm); + fclose(netstat); + } + if ((netstat = fopen("/proc/net/raw", "r")) != NULL) { + registerMonitor("network/sockets/raw/count", "integer", printNetStat, printNetStatInfo, sm); + registerMonitor("network/sockets/raw/list", "listview", printNetStatTcpUdpRaw, printNetStatTcpUdpRawInfo, sm); + fclose(netstat); + } + + TcpSocketList = new_ctnr(); + UdpSocketList = new_ctnr(); + RawSocketList = new_ctnr(); + UnixSocketList = new_ctnr(); +} + +void +exitNetStat(void) +{ + destr_ctnr(TcpSocketList, free); + destr_ctnr(UdpSocketList, free); + destr_ctnr(RawSocketList, free); + destr_ctnr(UnixSocketList, free); +} + +int +updateNetStat(void) +{ + FILE *netstat; + + if ((netstat = fopen("/proc/net/tcp", "r")) != NULL) { + num_tcp = get_num_sockets(netstat); + fclose(netstat); + } + + if ((netstat = fopen("/proc/net/udp", "r")) != NULL) { + num_udp = get_num_sockets(netstat); + fclose(netstat); + } + + if ((netstat = fopen("/proc/net/unix", "r")) != NULL) { + num_unix = get_num_sockets(netstat); + fclose(netstat); + } + if ((netstat = fopen("/proc/net/raw", "r")) != NULL) { + num_raw = get_num_sockets(netstat); + fclose(netstat); + } + + NetStat_timeStamp = time(0); + return 0; +} + +int +updateNetStatTcpUdpRaw(const char *cmd) +{ + FILE *netstat; + char buffer[1024]; + uint local_addr, local_port; + uint remote_addr, remote_port; + int uid, i; + uint state; + SocketInfo *socket_info; + + if (strstr(cmd, "tcp")) { + snprintf(buffer, sizeof(buffer), "/proc/net/tcp"); + for (i = level_ctnr(TcpSocketList); i >= 0; --i) + free(pop_ctnr(TcpSocketList)); + } + + if (strstr(cmd, "udp")) { + snprintf(buffer, sizeof(buffer), "/proc/net/udp"); + for (i = level_ctnr(UdpSocketList); i >= 0; --i) + free(pop_ctnr(UdpSocketList)); + } + + if (strstr(cmd, "raw")) { + snprintf(buffer, sizeof(buffer), "/proc/net/raw"); + for (i = level_ctnr(RawSocketList); i >= 0; --i) + free(pop_ctnr(RawSocketList)); + } + + if ((netstat = fopen(buffer, "r")) == NULL) { + print_error("Cannot open \'%s\'!\n" + "The kernel needs to be compiled with support\n" + "for /proc filesystem enabled!\n", buffer); + return -1; + } + + fgets(buffer, sizeof(buffer), netstat); + + while (fgets(buffer, sizeof(buffer), netstat) != NULL) { + if (strcmp(buffer, "")) { + sscanf(buffer, "%*d: %x:%x %x:%x %x %*x:%*x %*x:%*x %d", + &local_addr, &local_port, + &remote_addr, &remote_port, + &state, + &uid); + + if ((socket_info = (SocketInfo *)malloc(sizeof(SocketInfo))) == NULL) { + continue; + } + strlcpy(socket_info->local_addr, get_host_name(local_addr), sizeof(socket_info->local_addr)); + strlcpy(socket_info->remote_addr, get_host_name(remote_addr), sizeof(socket_info->remote_addr)); + + if (strstr(cmd, "tcp")) { + strlcpy(socket_info->local_port, get_serv_name(local_port, "tcp"), sizeof(socket_info->local_port)); + strlcpy(socket_info->remote_port, get_serv_name(remote_port, "tcp"), sizeof(socket_info->remote_port)); + strlcpy(socket_info->state, conn_state[state], sizeof(socket_info->state)); + socket_info->uid = uid; + + push_ctnr(TcpSocketList, socket_info); + } + + if (strstr(cmd, "udp")) { + strlcpy(socket_info->local_port, get_serv_name(local_port, "udp"), sizeof(socket_info->local_port)); + strlcpy(socket_info->remote_port, get_serv_name(remote_port, "udp"), sizeof(socket_info->remote_port)); + strlcpy(socket_info->state, conn_state[state], sizeof(socket_info->state)); + socket_info->uid = uid; + + push_ctnr(UdpSocketList, socket_info); + } + + if (strstr(cmd, "raw")) { + strlcpy(socket_info->local_port, get_proto_name(local_port), sizeof(socket_info->local_port)); + strlcpy(socket_info->remote_port, get_proto_name(remote_port), sizeof(socket_info->remote_port)); + snprintf(socket_info->state, sizeof(socket_info->state)-1, "%d", state); + socket_info->uid = uid; + + push_ctnr(RawSocketList, socket_info); + } + } + } + fclose(netstat); + TcpUdpRaw_timeStamp = time(0); + + return 0; +} + +int +updateNetStatUnix(void) +{ + FILE *file; + char buffer[1024]; + char path[256]; + int ref_count, type, state, inode, i; + UnixInfo *unix_info; + + if ((file = fopen("/proc/net/unix", "r")) == NULL) { + print_error("Cannot open \'/proc/net/unix\'!\n" + "The kernel needs to be compiled with support\n" + "for /proc filesystem enabled!\n"); + return -1; + } + + for (i = level_ctnr(UnixSocketList); i >= 0; --i) + free(pop_ctnr(UnixSocketList)); + + fgets(buffer, sizeof(buffer), file); + + while (fgets(buffer, sizeof(buffer), file) != NULL) { + if (strcmp(buffer, "")) { + sscanf(buffer, "%*x: %d %*d %*d %d %d %d %255s", + &ref_count, &type, &state, &inode, path); + + if ((unix_info = (UnixInfo *)malloc(sizeof(UnixInfo))) == NULL) { + continue; + } + + unix_info->refcount = ref_count; + strlcpy(unix_info->type, raw_type[type], sizeof(unix_info->type)); + strlcpy(unix_info->state, raw_state[state], sizeof(unix_info->state)); + unix_info->inode = inode; + strlcpy(unix_info->path, path, sizeof(unix_info->path)); + + push_ctnr(UnixSocketList, unix_info); + } + } + fclose(file); + Unix_timeStamp = time(0); + + return 0; +} + +void +printNetStat(const char* cmd) +{ + if ((time(0) - NetStat_timeStamp) >= UPDATEINTERVAL) + updateNetStat(); + + if (strstr(cmd, "tcp") != NULL) + fprintf(CurrentClient, "%d\n", num_tcp); + if (strstr(cmd, "udp") != NULL) + fprintf(CurrentClient, "%d\n", num_udp); + if (strstr(cmd, "unix") != NULL) + fprintf(CurrentClient, "%d\n", num_unix); + if (strstr(cmd, "raw") != NULL) + fprintf(CurrentClient, "%d\n", num_raw); +} + +void +printNetStatInfo(const char* cmd) +{ + if (strstr(cmd, "tcp") != NULL) + fprintf(CurrentClient, "Number of TCP-Sockets\t0\t0\tSockets\n"); + if (strstr(cmd, "udp") != NULL) + fprintf(CurrentClient, "Number of UDP-Sockets\t0\t0\tSockets\n"); + if (strstr(cmd, "unix") != NULL) + fprintf(CurrentClient, "Number of UnixDomain-Sockets\t0\t0\tSockets\n"); + if (strstr(cmd, "raw") != NULL) + fprintf(CurrentClient, "Number of Raw-Sockets\t0\t0\tSockets\n"); +} + +void +printNetStatTcpUdpRaw(const char *cmd) +{ + SocketInfo* socket_info; + + if (strstr(cmd, "tcp")) { + if ((time(0) - TcpUdpRaw_timeStamp) >= UPDATEINTERVAL) + updateNetStatTcpUdpRaw("tcp"); + + for (socket_info = first_ctnr(TcpSocketList); socket_info; socket_info = next_ctnr(TcpSocketList)) + printSocketInfo(socket_info); + + if (level_ctnr(TcpSocketList) == 0) + fprintf(CurrentClient, "\n"); + } + + if (strstr(cmd, "udp")) { + if ((time(0) - TcpUdpRaw_timeStamp) >= UPDATEINTERVAL) + updateNetStatTcpUdpRaw("udp"); + + for (socket_info = first_ctnr(UdpSocketList); socket_info; socket_info = next_ctnr(UdpSocketList)) + printSocketInfo(socket_info); + + if (level_ctnr(UdpSocketList) == 0) + fprintf(CurrentClient, "\n"); + } + + if (strstr(cmd, "raw")) { + if ((time(0) - TcpUdpRaw_timeStamp) >= UPDATEINTERVAL) + updateNetStatTcpUdpRaw("raw"); + + for (socket_info = first_ctnr(RawSocketList); socket_info; socket_info = next_ctnr(RawSocketList)) + printSocketInfo(socket_info); + + if (level_ctnr(RawSocketList) == 0) + fprintf(CurrentClient, "\n"); + } +} + +void +printNetStatTcpUdpRawInfo(const char *cmd) +{ + (void) cmd; + fprintf(CurrentClient, "Local Address\tPort\tForeign Address\tPort\tState\tUID\ns\ts\ts\ts\ts\td\n"); +} + +void printNetStatUnix(const char *cmd) +{ + UnixInfo* unix_info; + + (void) cmd; + if ((time(0) - Unix_timeStamp) >= UPDATEINTERVAL) + updateNetStatUnix(); + + for (unix_info = first_ctnr(UnixSocketList); unix_info; unix_info = next_ctnr(UnixSocketList)) { + fprintf(CurrentClient, "%d\t%s\t%s\t%d\t%s\n", + unix_info->refcount, + unix_info->type, + unix_info->state, + unix_info->inode, + unix_info->path); + } + + if (level_ctnr(UnixSocketList) == 0) + fprintf(CurrentClient, "\n"); +} + +void printNetStatUnixInfo(const char *cmd) +{ + (void) cmd; + fprintf(CurrentClient, "RefCount\tType\tState\tInode\tPath\nd\ts\ts\td\ts\n"); +} diff --git a/ksysguard/ksysguardd/Linux/netstat.h b/ksysguard/ksysguardd/Linux/netstat.h new file mode 100644 index 000000000..be0c3a850 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/netstat.h @@ -0,0 +1,39 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 _netstat_h_ +#define _netstat_h_ + +void initNetStat(struct SensorModul* sm); +void exitNetStat(void); + +int updateNetStat(void); +int updateNetStatTcpUdpRaw(const char* cmd); +int updateNetStatUnix(void); + +void printNetStat(const char* cmd); +void printNetStatInfo(const char* cmd); + +void printNetStatTcpUdpRaw(const char *cmd); +void printNetStatTcpUdpRawInfo(const char *cmd); + +void printNetStatUnix(const char *cmd); +void printNetStatUnixInfo(const char *cmd); +#endif diff --git a/ksysguard/ksysguardd/Linux/stat.c b/ksysguard/ksysguardd/Linux/stat.c new file mode 100644 index 000000000..0e03e4d53 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/stat.c @@ -0,0 +1,1184 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "Command.h" +#include "ksysguardd.h" + +#include "stat.h" + +typedef struct +{ + /* A CPU can be loaded with user processes, reniced processes and + * system processes. Unused processing time is called idle load. + * These variable store the percentage of each load type. */ + int userLoad; + int niceLoad; + int sysLoad; + int idleLoad; + + /* To calculate the loads we need to remember the tick values for each + * load type. */ + unsigned long userTicks; + unsigned long niceTicks; + unsigned long sysTicks; + unsigned long idleTicks; +} CPULoadInfo; + +typedef struct +{ + unsigned long delta; + unsigned long old; +} DiskLoadSample; + +typedef struct +{ + /* 5 types of samples are taken: + total, rio, wio, rBlk, wBlk */ + DiskLoadSample s[ 5 ]; +} DiskLoadInfo; + +typedef struct DiskIOInfo +{ + int major; + int minor; + int alive; + DiskLoadSample total; + DiskLoadSample rio; + DiskLoadSample wio; + DiskLoadSample rblk; + DiskLoadSample wblk; + struct DiskIOInfo* next; +} DiskIOInfo; + +#define STATBUFSIZE (32 * 1024) + +static char StatBuf[ STATBUFSIZE ]; +static char VmStatBuf[ STATBUFSIZE ]; +static char IOStatBuf[ STATBUFSIZE ]; /* Buffer for /proc/diskstats */ +static int Dirty = 0; + +/* We have observed deviations of up to 5% in the accuracy of the timer + * interrupts. So we try to measure the interrupt interval and use this + * value to calculate timing dependant values. */ +static float timeInterval = 0; +static struct timeval lastSampling; +static struct timeval currSampling; +static struct SensorModul* StatSM; + +static CPULoadInfo CPULoad; +static CPULoadInfo* SMPLoad = 0; +static unsigned CPUCount = 0; +static DiskLoadInfo* DiskLoad = 0; +static unsigned DiskCount = 0; +static DiskIOInfo* DiskIO = 0; +static unsigned long PageIn = 0; +static unsigned long OldPageIn = 0; +static unsigned long PageOut = 0; +static unsigned long OldPageOut = 0; +static unsigned long Ctxt = 0; +static unsigned long OldCtxt = 0; +static unsigned int NumOfInts = 0; +static unsigned long* OldIntr = 0; +static unsigned long* Intr = 0; + +static int initStatDisk( char* tag, char* buf, const char* label, const char* shortLabel, + int idx, cmdExecutor ex, cmdExecutor iq ); +static void updateCPULoad( const char* line, CPULoadInfo* load ); +static int processDisk( char* tag, char* buf, const char* label, int idx ); +static void processStat( void ); +static int processDiskIO( const char* buf ); +static int process26DiskIO( const char* buf ); +static void cleanupDiskList( void ); + +static int initStatDisk( char* tag, char* buf, const char* label, + const char* shortLabel, int idx, cmdExecutor ex, cmdExecutor iq ) +{ + char sensorName[ 128 ]; + + gettimeofday( &lastSampling, 0 ); + + if ( strcmp( label, tag ) == 0 ) { + unsigned int i; + buf = buf + strlen( label ) + 1; + + for ( i = 0; i < DiskCount; ++i ) { + sscanf( buf, "%lu", &DiskLoad[ i ].s[ idx ].old ); + while ( *buf && isblank( *buf++ ) ); + while ( *buf && isdigit( *buf++ ) ); + sprintf( sensorName, "disk/disk%d/%s", i, shortLabel ); + registerMonitor( sensorName, "integer", ex, iq, StatSM ); + } + + return 1; + } + + return 0; +} + +static void updateCPULoad( const char* line, CPULoadInfo* load ) +{ + unsigned long currUserTicks, currSysTicks, currNiceTicks, currIdleTicks; + unsigned long totalTicks; + + sscanf( line, "%*s %lu %lu %lu %lu", &currUserTicks, &currNiceTicks, + &currSysTicks, &currIdleTicks ); + + totalTicks = ( currUserTicks - load->userTicks ) + + ( currSysTicks - load->sysTicks ) + + ( currNiceTicks - load->niceTicks ) + + ( currIdleTicks - load->idleTicks ); + + if ( totalTicks > 10 ) { + load->userLoad = ( 100 * ( currUserTicks - load->userTicks ) ) / totalTicks; + load->sysLoad = ( 100 * ( currSysTicks - load->sysTicks ) ) / totalTicks; + load->niceLoad = ( 100 * ( currNiceTicks - load->niceTicks ) ) / totalTicks; + load->idleLoad = ( 100 - ( load->userLoad + load->sysLoad + load->niceLoad ) ); + } else + load->userLoad = load->sysLoad = load->niceLoad = load->idleLoad = 0; + + load->userTicks = currUserTicks; + load->sysTicks = currSysTicks; + load->niceTicks = currNiceTicks; + load->idleTicks = currIdleTicks; +} + +static int processDisk( char* tag, char* buf, const char* label, int idx ) +{ + if ( strcmp( label, tag ) == 0 ) { + unsigned long val; + unsigned int i; + buf = buf + strlen( label ) + 1; + + for ( i = 0; i < DiskCount; ++i ) { + sscanf( buf, "%lu", &val ); + while ( *buf && isblank( *buf++ ) ); + while ( *buf && isdigit( *buf++ ) ); + DiskLoad[ i ].s[ idx ].delta = val - DiskLoad[ i ].s[ idx ].old; + DiskLoad[ i ].s[ idx ].old = val; + } + + return 1; + } + + return 0; +} + +static int processDiskIO( const char* buf ) +{ + /* Process disk_io lines as provided by 2.4.x kernels. + * disk_io: (2,0):(3,3,6,0,0) (3,0):(1413012,511622,12155382,901390,26486215) */ + int major, minor; + unsigned long total, rblk, rio, wblk, wio; + DiskIOInfo* ptr = DiskIO; + DiskIOInfo* last = 0; + char sensorName[ 128 ]; + const char* p; + + p = buf + strlen( "disk_io: " ); + while ( p && *p ) { + if ( sscanf( p, "(%d,%d):(%lu,%lu,%lu,%lu,%lu)", &major, &minor, + &total, &rio, &rblk, &wio, &wblk ) != 7 ) + return -1; + + last = 0; + ptr = DiskIO; + while ( ptr ) { + if ( ptr->major == major && ptr->minor == minor ) { + /* The IO device has already been registered. */ + ptr->total.delta = total - ptr->total.old; + ptr->total.old = total; + ptr->rio.delta = rio - ptr->rio.old; + ptr->rio.old = rio; + ptr->wio.delta = wio - ptr->wio.old; + ptr->wio.old = wio; + ptr->rblk.delta = rblk - ptr->rblk.old; + ptr->rblk.old = rblk; + ptr->wblk.delta = wblk - ptr->wblk.old; + ptr->wblk.old = wblk; + ptr->alive = 1; + break; + } + last = ptr; + ptr = ptr->next; + } + + if ( !ptr ) { + /* The IO device has not been registered yet. We need to add it. */ + ptr = (DiskIOInfo*)malloc( sizeof( DiskIOInfo ) ); + ptr->major = major; + ptr->minor = minor; + ptr->total.delta = 0; + ptr->total.old = total; + ptr->rio.delta = 0; + ptr->rio.old = rio; + ptr->wio.delta = 0; + ptr->wio.old = wio; + ptr->rblk.delta = 0; + ptr->rblk.old = rblk; + ptr->wblk.delta = 0; + ptr->wblk.old = wblk; + ptr->alive = 1; + ptr->next = 0; + if ( last ) { + /* Append new entry at end of list. */ + last->next = ptr; + } else { + /* List is empty, so we insert the fist element into the list. */ + DiskIO = ptr; + } + + sprintf( sensorName, "disk/%d:%d/total", major, minor ); + registerMonitor( sensorName, "integer", printDiskIO, printDiskIOInfo, StatSM ); + sprintf( sensorName, "disk/%d:%d/rio", major, minor ); + registerMonitor( sensorName, "integer", printDiskIO, printDiskIOInfo, StatSM ); + sprintf( sensorName, "disk/%d:%d/wio", major, minor ); + registerMonitor( sensorName, "integer", printDiskIO, printDiskIOInfo, StatSM ); + sprintf( sensorName, "disk/%d:%d/rblk", major, minor ); + registerMonitor( sensorName, "integer", printDiskIO, printDiskIOInfo, StatSM ); + sprintf( sensorName, "disk/%d:%d/wblk", major, minor ); + registerMonitor( sensorName, "integer", printDiskIO, printDiskIOInfo, StatSM ); + } + /* Move p after the sencond ')'. We can safely assume that + * those two ')' exist. */ + p = strchr( p, ')' ) + 1; + p = strchr( p, ')' ) + 1; + if ( p && *p ) + p = strchr( p, '(' ); + } + + return 0; +} + +static int process26DiskIO( const char* buf ) +{ + /* Process values from /proc/diskstats (Linux >= 2.6.x) */ + + /* For each disk /proc/diskstats includes lines as follows: + * 3 0 hda 1314558 74053 26451438 14776742 1971172 4607401 52658448 202855090 0 9597019 217637839 + * 3 1 hda1 178 360 0 0 + * 3 2 hda2 354 360 0 0 + * 3 3 hda3 354 360 0 0 + * 3 4 hda4 0 0 0 0 + * 3 5 hda5 529506 9616000 4745856 37966848 + * + * - See Documentation/iostats.txt for details on the changes + */ + int major, minor; + char devname[16]; + unsigned long total, + rio, rmrg, rblk, rtim, + wio, wmrg, wblk, wtim, + ioprog, iotim, iotimw; + DiskIOInfo *ptr = DiskIO; + DiskIOInfo *last = 0; + char sensorName[128]; + + switch (sscanf(buf, "%d %d %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", + &major, &minor, devname, + &rio, &rmrg, &rblk, &rtim, + &wio, &wmrg, &wblk, &wtim, + &ioprog, &iotim, &iotimw)) + { + case 7: + /* Partition stats entry */ + /* Adjust read fields rio rmrg rblk rtim -> rio rblk wio wblk */ + wblk = rtim; + wio = rblk; + rblk = rmrg; + + total = rio + wio; + + break; + case 14: + /* Disk stats entry */ + total = rio + wio; + + break; + default: + /* Something unexepected */ + return -1; + } + + last = 0; + ptr = DiskIO; + while (ptr) + { + if (ptr->major == major && ptr->minor == minor) + { + /* The IO device has already been registered. */ + ptr->total.delta = total - ptr->total.old; + ptr->total.old = total; + ptr->rio.delta = rio - ptr->rio.old; + ptr->rio.old = rio; + ptr->wio.delta = wio - ptr->wio.old; + ptr->wio.old = wio; + ptr->rblk.delta = rblk - ptr->rblk.old; + ptr->rblk.old = rblk; + ptr->wblk.delta = wblk - ptr->wblk.old; + ptr->wblk.old = wblk; + ptr->alive = 1; + break; + } + + last = ptr; + ptr = ptr->next; + } + + if (!ptr) + { + /* The IO device has not been registered yet. We need to add it. */ + ptr = (DiskIOInfo*)malloc( sizeof( DiskIOInfo ) ); + ptr->major = major; + ptr->minor = minor; + ptr->total.delta = 0; + ptr->total.old = total; + ptr->rio.delta = 0; + ptr->rio.old = rio; + ptr->wio.delta = 0; + ptr->wio.old = wio; + ptr->rblk.delta = 0; + ptr->rblk.old = rblk; + ptr->wblk.delta = 0; + ptr->wblk.old = wblk; + ptr->alive = 1; + ptr->next = 0; + if (last) + { + /* Append new entry at end of list. */ + last->next = ptr; + } + else + { + /* List is empty, so we insert the fist element into the list. */ + DiskIO = ptr; + } + + sprintf(sensorName, "disk/%d:%d/total", major, minor); + registerMonitor(sensorName, "integer", printDiskIO, printDiskIOInfo, + StatSM); + sprintf(sensorName, "disk/%d:%d/rio", major, minor); + registerMonitor(sensorName, "integer", printDiskIO, printDiskIOInfo, + StatSM); + sprintf(sensorName, "disk/%d:%d/wio", major, minor); + registerMonitor(sensorName, "integer", printDiskIO, printDiskIOInfo, + StatSM); + sprintf(sensorName, "disk/%d:%d/rblk", major, minor); + registerMonitor(sensorName, "integer", printDiskIO, printDiskIOInfo, + StatSM); + sprintf(sensorName, "disk/%d:%d/wblk", major, minor); + registerMonitor(sensorName, "integer", printDiskIO, printDiskIOInfo, + StatSM); + } + + return 0; +} + +static void cleanupDiskList( void ) +{ + DiskIOInfo* ptr = DiskIO; + DiskIOInfo* last = 0; + + while ( ptr ) { + if ( ptr->alive == 0 ) { + DiskIOInfo* newPtr; + char sensorName[ 128 ]; + + /* Disk device has disappeared. We have to remove it from + * the list and unregister the monitors. */ + sprintf( sensorName, "disk/%d:%d/total", ptr->major, ptr->minor ); + removeMonitor( sensorName ); + sprintf( sensorName, "disk/%d:%d/rio", ptr->major, ptr->minor ); + removeMonitor( sensorName ); + sprintf( sensorName, "disk/%d:%d/wio", ptr->major, ptr->minor ); + removeMonitor( sensorName ); + sprintf( sensorName, "disk/%d:%d/rblk", ptr->major, ptr->minor ); + removeMonitor( sensorName ); + sprintf( sensorName, "disk/%d:%d/wblk", ptr->major, ptr->minor ); + removeMonitor( sensorName ); + if ( last ) { + last->next = ptr->next; + newPtr = ptr->next; + } else { + DiskIO = ptr->next; + newPtr = DiskIO; + last = 0; + } + + free ( ptr ); + ptr = newPtr; + } else { + ptr->alive = 0; + last = ptr; + ptr = ptr->next; + } + } +} + +static void processStat( void ) +{ + char format[ 32 ]; + char tagFormat[ 16 ]; + char buf[ 1024 ]; + char tag[ 32 ]; + char* statBufP = StatBuf; + char* vmstatBufP = VmStatBuf; + char* iostatBufP = IOStatBuf; + + sprintf( format, "%%%d[^\n]\n", (int)sizeof( buf ) - 1 ); + sprintf( tagFormat, "%%%ds", (int)sizeof( tag ) - 1 ); + + while ( sscanf( statBufP, format, buf ) == 1 ) { + buf[ sizeof( buf ) - 1 ] = '\0'; + statBufP += strlen( buf ) + 1; /* move statBufP to next line */ + sscanf( buf, tagFormat, tag ); + + if ( strcmp( "cpu", tag ) == 0 ) { + /* Total CPU load */ + updateCPULoad( buf, &CPULoad ); + } else if ( strncmp( "cpu", tag, 3 ) == 0 ) { + /* Load for each SMP CPU */ + int id; + sscanf( tag + 3, "%d", &id ); + updateCPULoad( buf, &SMPLoad[ id ] ); + } else if ( processDisk( tag, buf, "disk", 0 ) ) { + } else if ( processDisk( tag, buf, "disk_rio", 1 ) ) { + } else if ( processDisk( tag, buf, "disk_wio", 2 ) ) { + } else if ( processDisk( tag, buf, "disk_rblk", 3 ) ) { + } else if ( processDisk( tag, buf, "disk_wblk", 4 ) ) { + } else if ( strcmp( "disk_io:", tag ) == 0 ) { + processDiskIO( buf ); + } else if ( strcmp( "page", tag ) == 0 ) { + unsigned long v1, v2; + sscanf( buf + 5, "%lu %lu", &v1, &v2 ); + PageIn = v1 - OldPageIn; + OldPageIn = v1; + PageOut = v2 - OldPageOut; + OldPageOut = v2; + } else if ( strcmp( "intr", tag ) == 0 ) { + unsigned int i = 0; + char* p = buf + 5; + + for ( i = 0; i < NumOfInts; i++ ) { + unsigned long val; + + sscanf( p, "%lu", &val ); + Intr[ i ] = val - OldIntr[ i ]; + OldIntr[ i ] = val; + while ( *p && *p != ' ' ) + p++; + while ( *p && *p == ' ' ) + p++; + } + } else if ( strcmp( "ctxt", tag ) == 0 ) { + unsigned long val; + + sscanf( buf + 5, "%lu", &val ); + Ctxt = val - OldCtxt; + OldCtxt = val; + } + } + + /* Read Linux 2.5.x /proc/vmstat */ + while ( sscanf( vmstatBufP, format, buf ) == 1 ) { + buf[ sizeof( buf ) - 1 ] = '\0'; + vmstatBufP += strlen( buf ) + 1; /* move vmstatBufP to next line */ + sscanf( buf, tagFormat, tag ); + + if ( strcmp( "pgpgin", tag ) == 0 ) { + unsigned long v1; + sscanf( buf + 7, "%lu", &v1 ); + PageIn = v1 - OldPageIn; + OldPageIn = v1; + } else if ( strcmp( "pgpgout", tag ) == 0 ) { + unsigned long v1; + sscanf( buf + 7, "%lu", &v1 ); + PageOut = v1 - OldPageOut; + OldPageOut = v1; + } + } + + /* Process values from /proc/diskstats (Linux >= 2.6.x) */ + while (sscanf(iostatBufP, format, buf) == 1) + { + buf[sizeof(buf) - 1] = '\0'; + iostatBufP += strlen(buf) + 1; /* move IOstatBufP to next line */ + + process26DiskIO(buf); + } + + /* save exact time inverval between this and the last read of /proc/stat */ + timeInterval = currSampling.tv_sec - lastSampling.tv_sec + + ( currSampling.tv_usec - lastSampling.tv_usec ) / 1000000.0; + lastSampling = currSampling; + + cleanupDiskList(); + + Dirty = 0; +} + +/* +================================ public part ================================= +*/ + +void initStat( struct SensorModul* sm ) +{ + /* The CPU load is calculated from the values in /proc/stat. The cpu + * entry contains 4 counters. These counters count the number of ticks + * the system has spend on user processes, system processes, nice + * processes and idle time. + * + * SMP systems will have cpu1 to cpuN lines right after the cpu info. The + * format is identical to cpu and reports the information for each cpu. + * Linux kernels <= 2.0 do not provide this information! + * + * The /proc/stat file looks like this: + * + * cpu 1586 4 808 36274 + * disk 7797 0 0 0 + * disk_rio 6889 0 0 0 + * disk_wio 908 0 0 0 + * disk_rblk 13775 0 0 0 + * disk_wblk 1816 0 0 0 + * page 27575 1330 + * swap 1 0 + * intr 50444 38672 2557 0 0 0 0 2 0 2 0 0 3 1429 1 7778 0 + * ctxt 54155 + * btime 917379184 + * processes 347 + * + * Linux kernel >= 2.4.0 have one or more disk_io: lines instead of + * the disk_* lines. + * + * Linux kernel >= 2.6.x(?) have disk I/O stats in /proc/diskstats + * and no disk relevant lines are found in /proc/stat + */ + + char format[ 32 ]; + char tagFormat[ 16 ]; + char buf[ 1024 ]; + char tag[ 32 ]; + char* statBufP = StatBuf; + char* vmstatBufP = VmStatBuf; + char* iostatBufP = IOStatBuf; + + StatSM = sm; + + updateStat(); + + sprintf( format, "%%%d[^\n]\n", (int)sizeof( buf ) - 1 ); + sprintf( tagFormat, "%%%ds", (int)sizeof( tag ) - 1 ); + + while ( sscanf( statBufP, format, buf ) == 1 ) { + buf[ sizeof( buf ) - 1 ] = '\0'; + statBufP += strlen( buf ) + 1; /* move statBufP to next line */ + sscanf( buf, tagFormat, tag ); + + if ( strcmp( "cpu", tag ) == 0 ) { + /* Total CPU load */ + registerMonitor( "cpu/user", "integer", printCPUUser, printCPUUserInfo, StatSM ); + registerMonitor( "cpu/nice", "integer", printCPUNice, printCPUNiceInfo, StatSM ); + registerMonitor( "cpu/sys", "integer", printCPUSys, printCPUSysInfo, StatSM ); + registerMonitor( "cpu/idle", "integer", printCPUIdle, printCPUIdleInfo, StatSM ); + } else if ( strncmp( "cpu", tag, 3 ) == 0 ) { + char cmdName[ 24 ]; + /* Load for each SMP CPU */ + int id; + + sscanf( tag + 3, "%d", &id ); + CPUCount++; + sprintf( cmdName, "cpu%d/user", id ); + registerMonitor( cmdName, "integer", printCPUxUser, printCPUxUserInfo, StatSM ); + sprintf( cmdName, "cpu%d/nice", id ); + registerMonitor( cmdName, "integer", printCPUxNice, printCPUxNiceInfo, StatSM ); + sprintf( cmdName, "cpu%d/sys", id ); + registerMonitor( cmdName, "integer", printCPUxSys, printCPUxSysInfo, StatSM ); + sprintf( cmdName, "cpu%d/idle", id ); + registerMonitor( cmdName, "integer", printCPUxIdle, printCPUxIdleInfo, StatSM ); + } else if ( strcmp( "disk", tag ) == 0 ) { + unsigned long val; + char* b = buf + 5; + + /* Count the number of registered disks */ + for ( DiskCount = 0; *b && sscanf( b, "%lu", &val ) == 1; DiskCount++ ) { + while ( *b && isblank( *b++ ) ); + while ( *b && isdigit( *b++ ) ); + } + + if ( DiskCount > 0 ) + DiskLoad = (DiskLoadInfo*)malloc( sizeof( DiskLoadInfo ) * DiskCount ); + initStatDisk( tag, buf, "disk", "disk", 0, printDiskTotal, printDiskTotalInfo ); + } else if ( initStatDisk( tag, buf, "disk_rio", "rio", 1, printDiskRIO, + printDiskRIOInfo ) ); + else if ( initStatDisk( tag, buf, "disk_wio", "wio", 2, printDiskWIO, + printDiskWIOInfo ) ); + else if ( initStatDisk( tag, buf, "disk_rblk", "rblk", 3, printDiskRBlk, + printDiskRBlkInfo ) ); + else if ( initStatDisk( tag, buf, "disk_wblk", "wblk", 4, printDiskWBlk, + printDiskWBlkInfo ) ); + else if ( strcmp( "disk_io:", tag ) == 0 ) + processDiskIO( buf ); + else if ( strcmp( "page", tag ) == 0 ) { + sscanf( buf + 5, "%lu %lu", &OldPageIn, &OldPageOut ); + registerMonitor( "cpu/pageIn", "integer", printPageIn, + printPageInInfo, StatSM ); + registerMonitor( "cpu/pageOut", "integer", printPageOut, + printPageOutInfo, StatSM ); + } else if ( strcmp( "intr", tag ) == 0 ) { + unsigned int i; + char cmdName[ 32 ]; + char* p = buf + 5; + + /* Count the number of listed values in the intr line. */ + NumOfInts = 0; + while ( *p ) + if ( *p++ == ' ' ) + NumOfInts++; + + /* It looks like anything above 24 is always 0. So let's just + * ignore this for the time being. */ + if ( NumOfInts > 25 ) + NumOfInts = 25; + OldIntr = (unsigned long*)malloc( NumOfInts * sizeof( unsigned long ) ); + Intr = (unsigned long*)malloc( NumOfInts * sizeof( unsigned long ) ); + i = 0; + p = buf + 5; + for ( i = 0; p && i < NumOfInts; i++ ) { + sscanf( p, "%lu", &OldIntr[ i ] ); + while ( *p && *p != ' ' ) + p++; + while ( *p && *p == ' ' ) + p++; + sprintf( cmdName, "cpu/interrupts/int%02d", i ); + registerMonitor( cmdName, "integer", printInterruptx, + printInterruptxInfo, StatSM ); + } + } else if ( strcmp( "ctxt", tag ) == 0 ) { + sscanf( buf + 5, "%lu", &OldCtxt ); + registerMonitor( "cpu/context", "integer", printCtxt, + printCtxtInfo, StatSM ); + } + } + + while ( sscanf( vmstatBufP, format, buf ) == 1 ) { + buf[ sizeof( buf ) - 1 ] = '\0'; + vmstatBufP += strlen( buf ) + 1; /* move vmstatBufP to next line */ + sscanf( buf, tagFormat, tag ); + + if ( strcmp( "pgpgin", tag ) == 0 ) { + sscanf( buf + 7, "%lu", &OldPageIn ); + registerMonitor( "cpu/pageIn", "integer", printPageIn, + printPageInInfo, StatSM ); + } else if ( strcmp( "pgpgout", tag ) == 0 ) { + sscanf( buf + 7, "%lu", &OldPageOut ); + registerMonitor( "cpu/pageOut", "integer", printPageOut, + printPageOutInfo, StatSM ); + } + } + + /* Process values from /proc/diskstats (Linux >= 2.6.x) */ + while (sscanf(iostatBufP, format, buf) == 1) + { + buf[sizeof(buf) - 1] = '\0'; + iostatBufP += strlen(buf) + 1; /* move IOstatBufP to next line */ + + process26DiskIO(buf); + } + + if ( CPUCount > 0 ) + SMPLoad = (CPULoadInfo*)malloc( sizeof( CPULoadInfo ) * CPUCount ); + + /* Call processStat to eliminate initial peek values. */ + processStat(); +} + +void exitStat( void ) +{ + free( DiskLoad ); + DiskLoad = 0; + + free( SMPLoad ); + SMPLoad = 0; + + free( OldIntr ); + OldIntr = 0; + + free( Intr ); + Intr = 0; +} + +int updateStat( void ) +{ + size_t n; + int fd; + + if ( ( fd = open( "/proc/stat", O_RDONLY ) ) < 0 ) { + print_error( "Cannot open file \'/proc/stat\'!\n" + "The kernel needs to be compiled with support\n" + "for /proc filesystem enabled!\n" ); + return -1; + } + + if ( ( n = read( fd, StatBuf, STATBUFSIZE - 1 ) ) == STATBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'/proc/stat\'" ); + + close( fd ); + return -1; + } + + gettimeofday( &currSampling, 0 ); + close( fd ); + StatBuf[ n ] = '\0'; + Dirty = 1; + + VmStatBuf[ 0 ] = '\0'; + if ( ( fd = open( "/proc/vmstat", O_RDONLY ) ) < 0 ) + return 0; /* failure is okay, only exists for Linux >= 2.5.x */ + + if ( ( n = read( fd, VmStatBuf, STATBUFSIZE - 1 ) ) == STATBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'/proc/vmstat\'" ); + + close( fd ); + return -1; + } + + close( fd ); + VmStatBuf[ n ] = '\0'; + + /* Linux >= 2.6.x has disk I/O stats in /proc/diskstats */ + IOStatBuf[ 0 ] = '\0'; + if ( ( fd = open( "/proc/diskstats", O_RDONLY ) ) < 0 ) + return 0; /* failure is okay, only exists for Linux >= 2.6.x */ + + if ( ( n = read( fd, IOStatBuf, STATBUFSIZE - 1 ) ) == STATBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'/proc/diskstats\'" ); + + close( fd ); + return -1; + } + + close( fd ); + IOStatBuf[ n ] = '\0'; + + return 0; +} + +void printCPUUser( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processStat(); + + fprintf( CurrentClient, "%d\n", CPULoad.userLoad ); +} + +void printCPUUserInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "CPU User Load\t0\t100\t%%\n" ); +} + +void printCPUNice( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processStat(); + + fprintf( CurrentClient, "%d\n", CPULoad.niceLoad ); +} + +void printCPUNiceInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "CPU Nice Load\t0\t100\t%%\n" ); +} + +void printCPUSys( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processStat(); + + fprintf( CurrentClient, "%d\n", CPULoad.sysLoad ); +} + +void printCPUSysInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "CPU System Load\t0\t100\t%%\n" ); +} + +void printCPUIdle( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processStat(); + + fprintf( CurrentClient, "%d\n", CPULoad.idleLoad ); +} + +void printCPUIdleInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "CPU Idle Load\t0\t100\t%%\n" ); +} + +void printCPUxUser( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "%d\n", SMPLoad[ id ].userLoad ); +} + +void printCPUxUserInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "CPU%d User Load\t0\t100\t%%\n", id ); +} + +void printCPUxNice( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "%d\n", SMPLoad[ id ].niceLoad ); +} + +void printCPUxNiceInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "CPU%d Nice Load\t0\t100\t%%\n", id ); +} + +void printCPUxSys( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "%d\n", SMPLoad[ id ].sysLoad ); +} + +void printCPUxSysInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "CPU%d System Load\t0\t100\t%%\n", id ); +} + +void printCPUxIdle( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "%d\n", SMPLoad[ id ].idleLoad ); +} + +void printCPUxIdleInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 3, "%d", &id ); + fprintf( CurrentClient, "CPU%d Idle Load\t0\t100\t%%\n", id ); +} + +void printDiskTotal( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 9, "%d", &id ); + fprintf( CurrentClient, "%lu\n", (unsigned long)( DiskLoad[ id ].s[ 0 ].delta + / timeInterval ) ); +} + +void printDiskTotalInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 9, "%d", &id ); + fprintf( CurrentClient, "Disk%d Total Load\t0\t0\tkBytes/s\n", id ); +} + +void printDiskRIO( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 9, "%d", &id ); + fprintf( CurrentClient, "%lu\n", (unsigned long)( DiskLoad[ id ].s[ 1 ].delta + / timeInterval ) ); +} + +void printDiskRIOInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 9, "%d", &id ); + fprintf( CurrentClient, "Disk%d Read\t0\t0\tkBytes/s\n", id ); +} + +void printDiskWIO( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 9, "%d", &id ); + fprintf( CurrentClient, "%lu\n", (unsigned long)( DiskLoad[ id ].s[ 2 ].delta + / timeInterval ) ); +} + +void printDiskWIOInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 9, "%d", &id ); + fprintf( CurrentClient, "Disk%d Write\t0\t0\tkBytes/s\n", id ); +} + +void printDiskRBlk( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 9, "%d", &id ); + /* a block is 512 bytes or 1/2 kBytes */ + fprintf( CurrentClient, "%lu\n", (unsigned long)( DiskLoad[ id ].s[ 3 ].delta + / timeInterval * 2 ) ); +} + +void printDiskRBlkInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 9, "%d", &id ); + fprintf( CurrentClient, "Disk%d Read Data\t0\t0\tkBytes/s\n", id ); +} + +void printDiskWBlk( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + 9, "%d", &id ); + /* a block is 512 bytes or 1/2 kBytes */ + fprintf( CurrentClient, "%lu\n", (unsigned long)( DiskLoad[ id ].s[ 4 ].delta + / timeInterval * 2 ) ); +} + +void printDiskWBlkInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + 9, "%d", &id ); + fprintf( CurrentClient, "Disk%d Write Data\t0\t0\tkBytes/s\n", id ); +} + +void printPageIn( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processStat(); + + fprintf( CurrentClient, "%lu\n", (unsigned long)( PageIn / timeInterval ) ); +} + +void printPageInInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Paged in Pages\t0\t0\t1/s\n" ); +} + +void printPageOut( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processStat(); + + fprintf( CurrentClient, "%lu\n", (unsigned long)( PageOut / timeInterval ) ); +} + +void printPageOutInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Paged out Pages\t0\t0\t1/s\n" ); +} + +void printInterruptx( const char* cmd ) +{ + int id; + + if ( Dirty ) + processStat(); + + sscanf( cmd + strlen( "cpu/interrupts/int" ), "%d", &id ); + fprintf( CurrentClient, "%lu\n", (unsigned long)( Intr[ id ] / timeInterval ) ); +} + +void printInterruptxInfo( const char* cmd ) +{ + int id; + + sscanf( cmd + strlen( "cpu/interrupt/int" ), "%d", &id ); + fprintf( CurrentClient, "Interrupt %d\t0\t0\t1/s\n", id ); +} + +void printCtxt( const char* cmd ) +{ + (void)cmd; + + if ( Dirty ) + processStat(); + + fprintf( CurrentClient, "%lu\n", (unsigned long)( Ctxt / timeInterval ) ); +} + +void printCtxtInfo( const char* cmd ) +{ + (void)cmd; + fprintf( CurrentClient, "Context switches\t0\t0\t1/s\n" ); +} + +void printDiskIO( const char* cmd ) +{ + int major, minor; + char name[ 17 ]; + DiskIOInfo* ptr; + + sscanf( cmd, "disk/%d:%d/%16s", &major, &minor, name ); + + if ( Dirty ) + processStat(); + + ptr = DiskIO; + while ( ptr && ( ptr->major != major || ptr->minor != minor ) ) + ptr = ptr->next; + + if ( !ptr ) { + print_error( "RECONFIGURE" ); + fprintf( CurrentClient, "0\n" ); + + log_error( "Disk device disappeared" ); + return; + } + + if ( strcmp( name, "total" ) == 0 ) + fprintf( CurrentClient, "%lu\n", (unsigned long)( ptr->total.delta + / timeInterval ) ); + else if ( strcmp( name, "rio" ) == 0 ) + fprintf( CurrentClient, "%lu\n", (unsigned long)( ptr->rio.delta + / timeInterval ) ); + else if ( strcmp( name, "wio" ) == 0 ) + fprintf( CurrentClient, "%lu\n", (unsigned long)( ptr->wio.delta + / timeInterval ) ); + else if ( strcmp( name, "rblk" ) == 0 ) + fprintf( CurrentClient, "%lu\n", (unsigned long)( ptr->rblk.delta + / ( timeInterval * 2 ) ) ); + else if ( strcmp( name, "wblk" ) == 0 ) + fprintf( CurrentClient, "%lu\n", (unsigned long)( ptr->wblk.delta + / ( timeInterval * 2 ) ) ); + else { + fprintf( CurrentClient, "0\n" ); + log_error( "Unknown disk device property \'%s\'", name ); + } +} + +void printDiskIOInfo( const char* cmd ) +{ + int major, minor; + char name[ 17 ]; + DiskIOInfo* ptr = DiskIO; + + sscanf( cmd, "disk/%d:%d/%16s", &major, &minor, name ); + + while ( ptr && ( ptr->major != major || ptr->minor != minor ) ) + ptr = ptr->next; + + if ( !ptr ) { + /* Disk device has disappeared. Print a dummy answer. */ + fprintf( CurrentClient, "Dummy\t0\t0\t\n" ); + return; + } + + /* remove trailing '?' */ + name[ strlen( name ) - 1 ] = '\0'; + + if ( strcmp( name, "total" ) == 0 ) + fprintf( CurrentClient, "Total accesses device %d, %d\t0\t0\t1/s\n", + major, minor ); + else if ( strcmp( name, "rio" ) == 0 ) + fprintf( CurrentClient, "Read data device %d, %d\t0\t0\t1/s\n", + major, minor ); + else if ( strcmp( name, "wio" ) == 0 ) + fprintf( CurrentClient, "Write data device %d, %d\t0\t0\t1/s\n", + major, minor ); + else if ( strcmp( name, "rblk" ) == 0 ) + fprintf( CurrentClient, "Read accesses device %d, %d\t0\t0\tkBytes/s\n", + major, minor ); + else if ( strcmp( name, "wblk" ) == 0 ) + fprintf( CurrentClient, "Write accesses device %d, %d\t0\t0\tkBytes/s\n", + major, minor ); + else { + fprintf( CurrentClient, "Dummy\t0\t0\t\n" ); + log_error( "Request for unknown device property \'%s\'", name ); + } +} diff --git a/ksysguard/ksysguardd/Linux/stat.h b/ksysguard/ksysguardd/Linux/stat.h new file mode 100644 index 000000000..9107d3aa3 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/stat.h @@ -0,0 +1,66 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_STAT_H +#define KSG_STAT_H + +void initStat( struct SensorModul* ); +void exitStat( void ); + +int updateStat( void ); + +void printCPUUser( const char* ); +void printCPUUserInfo( const char* ); +void printCPUNice( const char* ); +void printCPUNiceInfo( const char* ); +void printCPUSys( const char* ); +void printCPUSysInfo( const char* ); +void printCPUIdle( const char* ); +void printCPUIdleInfo( const char* ); +void printCPUxUser( const char* ); +void printCPUxUserInfo( const char* ); +void printCPUxNice( const char* ); +void printCPUxNiceInfo( const char* ); +void printCPUxSys( const char* ); +void printCPUxSysInfo( const char* ); +void printCPUxIdle( const char* ); +void printCPUxIdleInfo( const char* ); +void printDiskTotal( const char* ); +void printDiskTotalInfo( const char* ); +void printDiskRIO( const char* ); +void printDiskRIOInfo( const char* ); +void printDiskWIO( const char* ); +void printDiskWIOInfo( const char* ); +void printDiskRBlk( const char* ); +void printDiskRBlkInfo( const char* ); +void printDiskWBlk( const char* ); +void printDiskWBlkInfo( const char* ); +void printPageIn( const char* ); +void printPageInInfo( const char* ); +void printPageOut( const char* ); +void printPageOutInfo( const char* ); +void printInterruptx( const char* ); +void printInterruptxInfo( const char* ); +void printCtxt( const char* ); +void printCtxtInfo( const char* ); +void printDiskIO( const char* ); +void printDiskIOInfo( const char* ); + +#endif diff --git a/ksysguard/ksysguardd/Makefile.am b/ksysguard/ksysguardd/Makefile.am new file mode 100644 index 000000000..485700780 --- /dev/null +++ b/ksysguard/ksysguardd/Makefile.am @@ -0,0 +1,35 @@ +AUTOMAKE_OPTIONS = foreign + +if include_ksysguardd_linux +linux_SUBDIR = Linux +endif +if include_ksysguardd_freebsd +freebsd_SUBDIR = FreeBSD +endif +if include_ksysguardd_netbsd +netbsd_SUBDIR = NetBSD +endif +if include_ksysguardd_solaris +solaris_SUBDIR = Solaris +endif +if include_ksysguardd_tru64 +tru64_SUBDIR = Tru64 +endif +if include_ksysguardd_irix +irix_SUBDIR = Irix +endif +if include_ksysguardd_openbsd +openbsd_SUBDIR = OpenBSD +endif + +SUBDIRS = $(linux_SUBDIR) $(freebsd_SUBDIR) $(netbsd_SUBDIR)\ + $(solaris_SUBDIR) $(tru64_SUBDIR) $(irix_SUBDIR) $(openbsd_SUBDIR) + +KSYSGUARDDRCFILE=$(sysconfdir)/ksysguarddrc +INCLUDES = -DKSYSGUARDDRCFILE="\"$(KSYSGUARDDRCFILE)\"" -DOSTYPE_$(UNAME) -I$(srcdir)/../CContLib -I$(srcdir)/$(UNAME) $(all_includes) + +bin_PROGRAMS = ksysguardd + +ksysguardd_SOURCES = Command.c conf.c ksysguardd.c PWUIDCache.c +ksysguardd_LDFLAGS = $(all_libraries) +ksysguardd_LDADD = $(top_builddir)/ksysguard/ksysguardd/$(UNAME)/libksysguardd.a ../CContLib/libccont.a -lkdefakes_nonpic $(LIBHOSTS) $(LIB_DNSSD) $(LIB_KINFO) diff --git a/ksysguard/ksysguardd/NetBSD/CPU.c b/ksysguard/ksysguardd/NetBSD/CPU.c new file mode 100644 index 000000000..959924087 --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/CPU.c @@ -0,0 +1,206 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@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 <sys/dkstat.h> +#include <sys/sched.h> /* CPUSTATES */ +#include <fcntl.h> +#include <kvm.h> +#include <nlist.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "CPU.h" +#include "Command.h" +#include "ksysguardd.h" + +long percentages(int cnt, int *out, long *new, long *old, long *diffs); + +struct nlist my_nlist[] = { + {"_cp_time"}, + { 0 } +}; + +kvm_t *kd; + +unsigned long cp_time_offset; + +long cp_time[CPUSTATES]; +long cp_old[CPUSTATES]; +long cp_diff[CPUSTATES]; +int cpu_states[CPUSTATES]; + +void +initCpuInfo(struct SensorModul* sm) +{ + /* Total CPU load */ + registerMonitor("cpu/user", "integer", printCPUUser, + printCPUUserInfo, sm); + registerMonitor("cpu/nice", "integer", printCPUNice, + printCPUNiceInfo, sm); + registerMonitor("cpu/sys", "integer", printCPUSys, + printCPUSysInfo, sm); + registerMonitor("cpu/idle", "integer", printCPUIdle, + printCPUIdleInfo, sm); + kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open"); + kvm_nlist(kd, my_nlist); + cp_time_offset = my_nlist[0].n_value; + + updateCpuInfo(); +} + +void +exitCpuInfo(void) +{ + kvm_close(kd); +} + +int +updateCpuInfo(void) +{ + kvm_read(kd, cp_time_offset, (char *)cp_time, sizeof(cp_time)); + percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); + return (0); +} + +void +printCPUUser(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", cpu_states[CP_USER]/10); +} + +void +printCPUUserInfo(const char* cmd) +{ + fprintf(CurrentClient, "CPU User Load\t0\t100\t%%\n"); +} + +void +printCPUNice(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", cpu_states[CP_NICE]/10); +} + +void +printCPUNiceInfo(const char* cmd) +{ + fprintf(CurrentClient, "CPU Nice Load\t0\t100\t%%\n"); +} + +void +printCPUSys(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", cpu_states[CP_SYS]/10); +} + +void +printCPUSysInfo(const char* cmd) +{ + fprintf(CurrentClient, "CPU System Load\t0\t100\t%%\n"); +} + +void +printCPUIdle(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", cpu_states[CP_IDLE]/10); +} + +void +printCPUIdleInfo(const char* cmd) +{ + fprintf(CurrentClient, "CPU Idle Load\t0\t100\t%%\n"); +} + + +/* The part ripped from top... */ +/* + * Top users/processes display for Unix + * Version 3 + * + * This program may be freely redistributed, + * but this entire comment MUST remain intact. + * + * Copyright (c) 1984, 1989, William LeFebvre, Rice University + * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University + */ + +/* + * percentages(cnt, out, new, old, diffs) - calculate percentage change + * between array "old" and "new", putting the percentages i "out". + * "cnt" is size of each array and "diffs" is used for scratch space. + * The array "old" is updated on each call. + * The routine assumes modulo arithmetic. This function is especially + * useful on BSD mchines for calculating cpu state percentages. + */ + +long percentages(cnt, out, new, old, diffs) + +int cnt; +int *out; +register long *new; +register long *old; +long *diffs; + +{ + register int i; + register long change; + register long total_change; + register long *dp; + long half_total; + + /* initialization */ + total_change = 0; + dp = diffs; + + /* calculate changes for each state and the overall change */ + for (i = 0; i < cnt; i++) + { + if ((change = *new - *old) < 0) + { + /* this only happens when the counter wraps */ + change = (int) + ((unsigned long)*new-(unsigned long)*old); + } + total_change += (*dp++ = change); + *old++ = *new++; + } + + /* avoid divide by zero potential */ + if (total_change == 0) + { + total_change = 1; + } + + /* calculate percentages based on overall change, rounding up */ + half_total = total_change / 2l; + + /* Do not divide by 0. Causes Floating point exception */ + if(total_change) { + for (i = 0; i < cnt; i++) + { + *out++ = (int)((*diffs++ * 1000 + half_total) / total_change); + } + } + + /* return the total in case the caller wants to use it */ + return(total_change); +} diff --git a/ksysguard/ksysguardd/NetBSD/CPU.h b/ksysguard/ksysguardd/NetBSD/CPU.h new file mode 100644 index 000000000..c35932ac8 --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/CPU.h @@ -0,0 +1,49 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@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 _cpuinfo_h_ +#define _cpuinfo_h_ + +struct SensorModul; + +void initCpuInfo(struct SensorModul* sm); +void exitCpuInfo(void); + +int updateCpuInfo(void); + +void printCPUUser(const char* cmd); +void printCPUUserInfo(const char* cmd); +void printCPUNice(const char* cmd); +void printCPUNiceInfo(const char* cmd); +void printCPUSys(const char* cmd); +void printCPUSysInfo(const char* cmd); +void printCPUIdle(const char* cmd); +void printCPUIdleInfo(const char* cmd); +void printCPUxUser(const char* cmd); +void printCPUxUserInfo(const char* cmd); +void printCPUxNice(const char* cmd); +void printCPUxNiceInfo(const char* cmd); +void printCPUxSys(const char* cmd); +void printCPUxSysInfo(const char* cmd); +void printCPUxIdle(const char* cmd); +void printCPUxIdleInfo(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/NetBSD/Makefile.am b/ksysguard/ksysguardd/NetBSD/Makefile.am new file mode 100644 index 000000000..29860a407 --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/Makefile.am @@ -0,0 +1,8 @@ +# +# + +INCLUDES = -I$(srcdir)/../../CContLib -I$(srcdir)/.. + +noinst_LIBRARIES = libksysguardd.a +libksysguardd_a_SOURCES = CPU.c Memory.c ProcessList.c apm.c diskstat.c \ + loadavg.c logfile.c netdev.c diff --git a/ksysguard/ksysguardd/NetBSD/Memory.c b/ksysguard/ksysguardd/NetBSD/Memory.c new file mode 100644 index 000000000..8e9779506 --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/Memory.c @@ -0,0 +1,202 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999-2000 Hans Petter Bieker <bieker@kde.org> + Copyright (c) 1999 Chris Schlaeger <cs@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 <fcntl.h> +#include <kvm.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/types.h> +#include <sys/vmmeter.h> +#include <unistd.h> +/* Everything post 1.5.x uses uvm/uvm_* includes */ +#if __NetBSD_Version__ >= 105010000 +#include <uvm/uvm_param.h> +#else +#include <vm/vm_param.h> +#endif + +#include "Command.h" +#include "Memory.h" +#include "ksysguardd.h" + +static size_t Total = 0; +static size_t MFree = 0; +static size_t Used = 0; +static size_t Buffers = 0; +static size_t Cached = 0; +static size_t STotal = 0; +static size_t SFree = 0; +static size_t SUsed = 0; +static kvm_t *kd; + +void +initMemory(struct SensorModul* sm) +{ + char *nlistf = NULL; + char *memf = NULL; + char buf[_POSIX2_LINE_MAX]; + + if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == NULL) { + log_error("kvm_openfiles()"); + return; + } + + registerMonitor("mem/physical/free", "integer", printMFree, printMFreeInfo, sm); + registerMonitor("mem/physical/used", "integer", printUsed, printUsedInfo, sm); + registerMonitor("mem/physical/buf", "integer", printBuffers, printBuffersInfo, sm); + registerMonitor("mem/physical/cached", "integer", printCached, printCachedInfo, sm); + registerMonitor("mem/swap/free", "integer", printSwapFree, printSwapFreeInfo, sm); + registerMonitor("mem/swap/used", "integer", printSwapUsed, printSwapUsedInfo, sm); +} + +void +exitMemory(void) +{ + kvm_close(kd); +} + +int +updateMemory(void) +{ + +#define ARRLEN(X) (sizeof(X)/sizeof(X[0])) + long pagesize; /* using a long promotes the arithmetic */ + size_t len; + + { + static int mib[]={ CTL_HW, HW_PHYSMEM }; + + len = sizeof(Total); + sysctl(mib, ARRLEN(mib), &Total, &len, NULL, 0); + Total >>= 10; + } + + { + struct uvmexp x; + static int mib[] = { CTL_VM, VM_UVMEXP }; + + len = sizeof(x); + STotal = SUsed = SFree = -1; + pagesize = 1; + if (-1 < sysctl(mib, ARRLEN(mib), &x, &len, NULL, 0)) { + pagesize = x.pagesize; + STotal = (pagesize*x.swpages) >> 10; + SUsed = (pagesize*x.swpginuse) >> 10; + SFree = STotal - SUsed; + } + } + + /* can't find NetBSD filesystem buffer info */ + Buffers = -1; + + /* NetBSD doesn't know about vm.stats */ + Cached = -1; + + { + static int mib[]={ CTL_VM, VM_METER }; + struct vmtotal x; + + len = sizeof(x); + MFree = Used = -1; + if (sysctl(mib, ARRLEN(mib), &x, &len, NULL, 0) > -1) { + MFree = (x.t_free * pagesize) >> 10; + Used = (x.t_rm * pagesize) >> 10; + } + } + return 0; +} + +void +printMFree(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", MFree); +} + +void +printMFreeInfo(const char* cmd) +{ + fprintf(CurrentClient, "Free Memory\t0\t%d\tKB\n", Total); +} + +void +printUsed(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", Used); +} + +void +printUsedInfo(const char* cmd) +{ + fprintf(CurrentClient, "Used Memory\t0\t%d\tKB\n", Total); +} + +void +printBuffers(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", Buffers); +} + +void +printBuffersInfo(const char* cmd) +{ + fprintf(CurrentClient, "Buffer Memory\t0\t%d\tKB\n", Total); +} + +void +printCached(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", Cached); +} + +void +printCachedInfo(const char* cmd) +{ + fprintf(CurrentClient, "Cached Memory\t0\t%d\tKB\n", Total); +} + +void +printSwapUsed(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", SUsed); +} + +void +printSwapUsedInfo(const char* cmd) +{ + fprintf(CurrentClient, "Used Swap Memory\t0\t%d\tKB\n", STotal); +} + +void +printSwapFree(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", SFree); +} + +void +printSwapFreeInfo(const char* cmd) +{ + fprintf(CurrentClient, "Free Swap Memory\t0\t%d\tKB\n", STotal); +} diff --git a/ksysguard/ksysguardd/NetBSD/Memory.h b/ksysguard/ksysguardd/NetBSD/Memory.h new file mode 100644 index 000000000..57abb73a2 --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/Memory.h @@ -0,0 +1,43 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@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 _memory_h_ +#define _memory_h_ + +void initMemory(struct SensorModul* sm); +void exitMemory(void); + +int updateMemory(void); + +void printMFree(const char* cmd); +void printMFreeInfo(const char* cmd); +void printUsed(const char* cmd); +void printUsedInfo(const char* cmd); +void printBuffers(const char* cmd); +void printBuffersInfo(const char* cmd); +void printCached(const char* cmd); +void printCachedInfo(const char* cmd); +void printSwapUsed(const char* cmd); +void printSwapUsedInfo(const char* cmd); +void printSwapFree(const char* cmd); +void printSwapFreeInfo(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/NetBSD/ProcessList.c b/ksysguard/ksysguardd/NetBSD/ProcessList.c new file mode 100644 index 000000000..54ab65513 --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/ProcessList.c @@ -0,0 +1,457 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999-2000 Hans Petter Bieker<bieker@kde.org> + Copyright (c) 1999 Chris Schlaeger <cs@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 <config.h> + +#include <ctype.h> +#include <dirent.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/user.h> +#include <unistd.h> +#include <signal.h> + +#include "../../gui/SignalIDs.h" +#include "Command.h" +#include "ProcessList.h" +#include "ccont.h" +#include "ksysguardd.h" + +CONTAINER ProcessList = 0; + +#define BUFSIZE 1024 + +typedef struct +{ + /* This flag is set for all found processes at the beginning of the + * process list update. Processes that do not have this flag set will + * be assumed dead and removed from the list. The flag is cleared after + * each list update. */ + int alive; + + /* the process ID */ + pid_t pid; + + /* the parent process ID */ + pid_t ppid; + + /* the real user ID */ + uid_t uid; + + /* the real group ID */ + gid_t gid; + + /* a character description of the process status */ + char status[16]; + + /* the number of the tty the process owns */ + int ttyNo; + + /* + * The nice level. The range should be -20 to 20. I'm not sure + * whether this is true for all platforms. + */ + int niceLevel; + + /* + * The scheduling priority. + */ + int priority; + + /* + * The total amount of memory the process uses. This includes shared and + * swapped memory. + */ + unsigned int vmSize; + + /* + * The amount of physical memory the process currently uses. + */ + unsigned int vmRss; + + /* + * The amount of memory (shared/swapped/etc) the process shares with + * other processes. + */ + unsigned int vmLib; + + /* + * The number of 1/100 of a second the process has spend in user space. + * If a machine has an uptime of 1 1/2 years or longer this is not a + * good idea. I never thought that the stability of UNIX could get me + * into trouble! ;) + */ + unsigned int userTime; + + /* + * The number of 1/100 of a second the process has spend in system space. + * If a machine has an uptime of 1 1/2 years or longer this is not a + * good idea. I never thought that the stability of UNIX could get me + * into trouble! ;) + */ + unsigned int sysTime; + + /* system time as multime of 100ms */ + int centStamp; + + /* the current CPU load (in %) from user space */ + double userLoad; + + /* the current CPU load (in %) from system space */ + double sysLoad; + + /* the name of the process */ + char name[64]; + + /* the command used to start the process */ + char cmdline[256]; + + /* the login name of the user that owns this process */ + char userName[32]; +} ProcessInfo; + +static unsigned ProcessCount; + +static int +processCmp(void* p1, void* p2) +{ + return (((ProcessInfo*) p1)->pid - ((ProcessInfo*) p2)->pid); +} + +static ProcessInfo* +findProcessInList(int pid) +{ + ProcessInfo key; + long index; + + key.pid = pid; + if ((index = search_ctnr(ProcessList, processCmp, &key)) < 0) + return (0); + + return (get_ctnr(ProcessList, index)); +} + +static int +updateProcess(int pid) +{ + static char *statuses[] = { "idle","run","sleep","stop","zombie" }; + + ProcessInfo* ps; + struct passwd* pwent; + int mib[4]; + struct kinfo_proc p; + size_t len; + + if ((ps = findProcessInList(pid)) == 0) + { + ps = (ProcessInfo*) malloc(sizeof(ProcessInfo)); + ps->pid = pid; + ps->centStamp = 0; + push_ctnr(ProcessList, ps); + bsort_ctnr(ProcessList, processCmp); + } + + ps->alive = 1; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = pid; + + len = sizeof (p); + if (sysctl(mib, 4, &p, &len, NULL, 0) == -1 || !len) + return -1; + + ps->pid = p.kp_proc.p_pid; + ps->ppid = p.kp_eproc.e_ppid; + ps->uid = p.kp_eproc.e_ucred.cr_uid; + ps->gid = p.kp_eproc.e_pgid; + ps->priority = p.kp_proc.p_priority; + ps->niceLevel = p.kp_proc.p_nice; + + /* this isn't usertime -- it's total time (??) */ + ps->userTime = p.kp_proc.p_rtime.tv_sec*100+p.kp_proc.p_rtime.tv_usec/100; + ps->sysTime = 0; + ps->sysLoad = 0; + + /* memory, process name, process uid */ + /* find out user name with process uid */ + pwent = getpwuid(ps->uid); + strlcpy(ps->userName,pwent&&pwent->pw_name? pwent->pw_name:"????",sizeof(ps->userName)); + ps->userName[sizeof(ps->userName)-1]='\0'; + + ps->userLoad = p.kp_proc.p_pctcpu / 100; + ps->vmSize = (p.kp_eproc.e_vm.vm_tsize + + p.kp_eproc.e_vm.vm_dsize + + p.kp_eproc.e_vm.vm_ssize) * getpagesize(); + ps->vmRss = p.kp_eproc.e_vm.vm_rssize * getpagesize(); + strlcpy(ps->name,p.kp_proc.p_comm ? p.kp_proc.p_comm : "????", sizeof(ps->name)); + strlcpy(ps->status,(p.kp_proc.p_stat>=1)&&(p.kp_proc.p_stat<=5)? statuses[p.kp_proc.p_stat-1]:"????", sizeof(ps->status)); + + /* process command line */ + /* the following line causes segfaults on some FreeBSD systems... why? + strncpy(ps->cmdline, p.kp_proc.p_args->ar_args, sizeof(ps->cmdline) - 1); + */ + strcpy(ps->cmdline, "????"); + + return (0); +} + +static void +cleanupProcessList(void) +{ + ProcessInfo* ps; + + ProcessCount = 0; + /* All processes that do not have the active flag set are assumed dead + * and will be removed from the list. The alive flag is cleared. */ + for (ps = first_ctnr(ProcessList); ps; ps = next_ctnr(ProcessList)) + { + if (ps->alive) + { + /* Process is still alive. Just clear flag. */ + ps->alive = 0; + ProcessCount++; + } + else + { + /* Process has probably died. We remove it from the list and + * destruct the data structure. i needs to be decremented so + * that after i++ the next list element will be inspected. */ + free(remove_ctnr(ProcessList)); + } + } +} + +/* +================================ public part ================================== +*/ + +void +initProcessList(struct SensorModul* sm) +{ + ProcessList = new_ctnr(); + + registerMonitor("ps", "table", printProcessList, printProcessListInfo, sm); + registerMonitor("pscount", "integer", printProcessCount, printProcessCountInfo, sm); + + if (!RunAsDaemon) + { + registerCommand("kill", killProcess); + registerCommand("setpriority", setPriority); + } + + updateProcessList(); +} + +void +exitProcessList(void) +{ + removeMonitor("ps"); + removeMonitor("pscount"); + + if (ProcessList) + free (ProcessList); +} + +int +updateProcessList(void) +{ + 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 = malloc(len); + sysctl(mib, 3, p, &len, NULL, 0); + + for (num = 0; num < len / sizeof(struct kinfo_proc); num++) + updateProcess(p[num].kp_proc.p_pid); + free(p); + cleanupProcessList(); + + return (0); +} + +void +printProcessListInfo(const char* cmd) +{ + fprintf(CurrentClient, "Name\tPID\tPPID\tUID\tGID\tStatus\tUser%%\tSystem%%\tNice\tVmSize\tVmRss\tLogin\tCommand\n"); + fprintf(CurrentClient, "s\td\td\td\td\tS\tf\tf\td\tD\tD\ts\ts\n"); +} + +void +printProcessList(const char* cmd) +{ + ProcessInfo* ps; + + ps = first_ctnr(ProcessList); /* skip 'kernel' entry */ + for (ps = next_ctnr(ProcessList); ps; ps = next_ctnr(ProcessList)) + { + fprintf(CurrentClient, "%s\t%ld\t%ld\t%ld\t%ld\t%s\t%.2f\t%.2f\t%d\t%d\t%d\t%s\t%s\n", + ps->name, (long)ps->pid, (long)ps->ppid, + (long)ps->uid, (long)ps->gid, ps->status, + ps->userLoad, ps->sysLoad, ps->niceLevel, + ps->vmSize / 1024, ps->vmRss / 1024, ps->userName, ps->cmdline); + } +} + +void +printProcessCount(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", ProcessCount); +} + +void +printProcessCountInfo(const char* cmd) +{ + fprintf(CurrentClient, "Number of Processes\t1\t65535\t\n"); +} + +void +killProcess(const char* cmd) +{ + int sig, pid; + + sscanf(cmd, "%*s %d %d", &pid, &sig); + switch(sig) + { + case MENU_ID_SIGABRT: + sig = SIGABRT; + break; + case MENU_ID_SIGALRM: + sig = SIGALRM; + break; + case MENU_ID_SIGCHLD: + sig = SIGCHLD; + break; + case MENU_ID_SIGCONT: + sig = SIGCONT; + break; + case MENU_ID_SIGFPE: + sig = SIGFPE; + break; + case MENU_ID_SIGHUP: + sig = SIGHUP; + break; + case MENU_ID_SIGILL: + sig = SIGILL; + break; + case MENU_ID_SIGINT: + sig = SIGINT; + break; + case MENU_ID_SIGKILL: + sig = SIGKILL; + break; + case MENU_ID_SIGPIPE: + sig = SIGPIPE; + break; + case MENU_ID_SIGQUIT: + sig = SIGQUIT; + break; + case MENU_ID_SIGSEGV: + sig = SIGSEGV; + break; + case MENU_ID_SIGSTOP: + sig = SIGSTOP; + break; + case MENU_ID_SIGTERM: + sig = SIGTERM; + break; + case MENU_ID_SIGTSTP: + sig = SIGTSTP; + break; + case MENU_ID_SIGTTIN: + sig = SIGTTIN; + break; + case MENU_ID_SIGTTOU: + sig = SIGTTOU; + break; + case MENU_ID_SIGUSR1: + sig = SIGUSR1; + break; + case MENU_ID_SIGUSR2: + sig = SIGUSR2; + break; + } + if (kill((pid_t) pid, sig)) + { + switch(errno) + { + case EINVAL: + fprintf(CurrentClient, "4\t%d\n", pid); + break; + case ESRCH: + fprintf(CurrentClient, "3\t%d\n", pid); + break; + case EPERM: + fprintf(CurrentClient, "2\t%d\n", pid); + break; + default: + fprintf(CurrentClient, "1\t%d\n", pid); /* unknown error */ + break; + } + + } + else + fprintf(CurrentClient, "0\t%d\n", pid); +} + +void +setPriority(const char* cmd) +{ + int pid, prio; + + sscanf(cmd, "%*s %d %d", &pid, &prio); + if (setpriority(PRIO_PROCESS, pid, prio)) + { + switch(errno) + { + case EINVAL: + fprintf(CurrentClient, "4\n"); + break; + case ESRCH: + fprintf(CurrentClient, "3\n"); + break; + case EPERM: + case EACCES: + fprintf(CurrentClient, "2\n"); + break; + default: + fprintf(CurrentClient, "1\n"); /* unknown error */ + break; + } + } + else + fprintf(CurrentClient, "0\n"); +} diff --git a/ksysguard/ksysguardd/NetBSD/ProcessList.h b/ksysguard/ksysguardd/NetBSD/ProcessList.h new file mode 100644 index 000000000..925c55f5a --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/ProcessList.h @@ -0,0 +1,38 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@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 _process_list_h_ +#define _process_list_h_ + +void initProcessList(struct SensorModul* sm); +void exitProcessList(void); + +int updateProcessList(void); + +void printProcessList(const char*); +void printProcessListInfo(const char*); +void printProcessCount(const char* cmd); +void printProcessCountInfo(const char* cmd); + +void killProcess(const char* cmd); +void setPriority(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/NetBSD/apm.c b/ksysguard/ksysguardd/NetBSD/apm.c new file mode 100644 index 000000000..f24887483 --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/apm.c @@ -0,0 +1,100 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <fcntl.h> +#include <machine/apmvar.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <stdio.h> + +#include "Command.h" +#include "apm.h" +#include "ksysguardd.h" + +static int ApmFD, BattFill, BattTime; + +#define APMDEV "/dev/apm" + +/* +================================ public part ================================= +*/ + +void +initApm(struct SensorModul* sm) +{ + if ((ApmFD = open(APMDEV, O_RDONLY)) < 0) + return; + + if (updateApm() < 0) + return; + + registerMonitor("apm/batterycharge", "integer", printApmBatFill, + printApmBatFillInfo, sm); + registerMonitor("apm/remainingtime", "integer", printApmBatTime, + printApmBatTimeInfo, sm); +} + +void +exitApm(void) +{ + removeMonitor("apm/batterycharge"); + removeMonitor("apm/remainingtime"); + + close(ApmFD); +} + +int +updateApm(void) +{ + int retval; + struct apm_power_info info; + retval = ioctl(ApmFD, APM_IOC_GETPOWER, &info); + + BattFill = info.battery_life; + BattTime = info.minutes_left; + + return retval; +} + +void +printApmBatFill(const char* c) +{ + fprintf(CurrentClient, "%d\n", BattFill); +} + +void +printApmBatFillInfo(const char* c) +{ + fprintf(CurrentClient, "Battery charge\t0\t100\t%%\n"); +} + +void +printApmBatTime(const char* c) +{ + fprintf(CurrentClient, "%d\n", BattTime); +} + +void +printApmBatTimeInfo(const char* c) +{ + fprintf(CurrentClient, "Remaining battery time\t0\t0\tmin\n"); +} + diff --git a/ksysguard/ksysguardd/NetBSD/apm.h b/ksysguard/ksysguardd/NetBSD/apm.h new file mode 100644 index 000000000..4e3c0c0d3 --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/apm.h @@ -0,0 +1,34 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 _apm_h_ +#define _apm_h_ + +void initApm(struct SensorModul* sm); +void exitApm(void); + +int updateApm(void); + +void printApmBatFill(const char*); +void printApmBatFillInfo(const char*); +void printApmBatTime(const char*); +void printApmBatTimeInfo(const char*); + +#endif diff --git a/ksysguard/ksysguardd/NetBSD/diskstat.c b/ksysguard/ksysguardd/NetBSD/diskstat.c new file mode 100644 index 000000000..818eee1d4 --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/diskstat.c @@ -0,0 +1,249 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/ucred.h> +#include <sys/mount.h> +#include <time.h> +#include <unistd.h> + +#include "Command.h" +#include "ccont.h" +#include "diskstat.h" +#include "ksysguardd.h" + +typedef struct { + char device[256]; + char mntpnt[256]; + long blocks; + long bfree; + long bused; + int bused_percent; +} DiskInfo; + +static CONTAINER DiskStatList = 0; +static struct SensorModul* DiskStatSM; + +char *getMntPnt(const char *cmd) +{ + static char device[1025]; + char *ptr; + + memset(device, 0, sizeof(device)); + sscanf(cmd, "partitions%1024s", device); + + ptr = (char *)rindex(device, '/'); + *ptr = '\0'; + + return (char *)device; +} + +int numMntPnt(void) +{ + struct statfs *fs_info; + int i, n, counter = 0; + + n = getmntinfo(&fs_info, MNT_WAIT); + for (i = 0; i < n; i++) + if (strcmp(fs_info[i].f_fstypename, "procfs") && strcmp(fs_info[i].f_fstypename, "swap") && strcmp(fs_info[i].f_fstypename, "devfs")) + counter++; + + return counter; +} + +/* ------------------------------ public part --------------------------- */ + +void initDiskStat(struct SensorModul* sm) +{ + char monitor[1024]; + DiskInfo* disk_info; + + DiskStatList = new_ctnr(); + DiskStatSM = sm; + + updateDiskStat(); + + registerMonitor("partitions/list", "listview", printDiskStat, printDiskStatInfo, DiskStatSM); + + for (disk_info = first_ctnr(DiskStatList); disk_info; disk_info = next_ctnr(DiskStatList)) { + snprintf(monitor, sizeof(monitor), "partitions%s/usedspace", disk_info->mntpnt); + registerMonitor(monitor, "integer", printDiskStatUsed, printDiskStatUsedInfo, DiskStatSM); + snprintf(monitor, sizeof(monitor), "partitions%s/freespace", disk_info->mntpnt); + registerMonitor(monitor, "integer", printDiskStatFree, printDiskStatFreeInfo, DiskStatSM); + snprintf(monitor, sizeof(monitor), "partitions%s/filllevel", disk_info->mntpnt); + registerMonitor(monitor, "integer", printDiskStatPercent, printDiskStatPercentInfo, DiskStatSM); + } +} + +void checkDiskStat(void) +{ + if (numMntPnt() != level_ctnr(DiskStatList)) { + /* a filesystem was mounted or unmounted + so we do a reset */ + exitDiskStat(); + initDiskStat(DiskStatSM); + } +} + +void exitDiskStat(void) +{ + DiskInfo *disk_info; + char monitor[1024]; + + removeMonitor("partitions/list"); + + for (disk_info = first_ctnr(DiskStatList); disk_info; disk_info = next_ctnr(DiskStatList)) { + snprintf(monitor, sizeof(monitor), "partitions%s/usedspace", disk_info->mntpnt); + removeMonitor(monitor); + snprintf(monitor, sizeof(monitor), "partitions%s/freespace", disk_info->mntpnt); + removeMonitor(monitor); + snprintf(monitor, sizeof(monitor), "partitions%s/filllevel", disk_info->mntpnt); + removeMonitor(monitor); + } + + destr_ctnr(DiskStatList, free); +} + +int updateDiskStat(void) +{ + struct statfs *fs_info; + struct statfs fs; + float percent; + int i, mntcount; + DiskInfo *disk_info; + + /* let's hope there is no difference between the DiskStatList and + the number of mounted filesystems */ + for (i = level_ctnr(DiskStatList); i >= 0; --i) + free(pop_ctnr(DiskStatList)); + + mntcount = getmntinfo(&fs_info, MNT_WAIT); + + for (i = 0; i < mntcount; i++) { + fs = fs_info[i]; + if (strcmp(fs.f_fstypename, "procfs") && strcmp(fs.f_fstypename, "devfs") && strcmp(fs.f_fstypename, "devfs")) { + percent = (((float)fs.f_blocks - (float)fs.f_bfree)/(float)fs.f_blocks); + percent = percent * 100; + if ((disk_info = (DiskInfo *)malloc(sizeof(DiskInfo))) == NULL) { + continue; + } + memset(disk_info, 0, sizeof(DiskInfo)); + strlcpy(disk_info->device, fs.f_mntfromname, sizeof(disk_info->device)); + if (!strcmp(fs.f_mntonname, "/")) { + strncpy(disk_info->mntpnt, "/root", 6); + } else { + strlcpy(disk_info->mntpnt, fs.f_mntonname, sizeof(disk_info->mntpnt)); + } + disk_info->blocks = fs.f_blocks; + disk_info->bfree = fs.f_bfree; + disk_info->bused = (fs.f_blocks - fs.f_bfree); + disk_info->bused_percent = (int)percent; + + push_ctnr(DiskStatList, disk_info); + } + } + + return 0; +} + +void printDiskStat(const char* cmd) +{ + DiskInfo* disk_info; + + for (disk_info = first_ctnr(DiskStatList); disk_info; disk_info = next_ctnr(DiskStatList)) { + fprintf(CurrentClient, "%s\t%ld\t%ld\t%ld\t%d\t%s\n", + disk_info->device, + disk_info->blocks, + disk_info->bused, + disk_info->bfree, + disk_info->bused_percent, + disk_info->mntpnt); + } + + fprintf(CurrentClient, "\n"); +} + +void printDiskStatInfo(const char* cmd) +{ + fprintf(CurrentClient, "Device\tBlocks\tUsed\tAvailable\tUsed %%\tMountPoint\nM\tD\tD\tD\td\ts\n"); +} + +void printDiskStatUsed(const char* cmd) +{ + DiskInfo* disk_info; + char *mntpnt = (char *)getMntPnt(cmd); + + for (disk_info = first_ctnr(DiskStatList); disk_info; disk_info = next_ctnr(DiskStatList)) { + if (!strcmp(mntpnt, disk_info->mntpnt)) { + fprintf(CurrentClient, "%ld\n", disk_info->bused); + } + } + + fprintf(CurrentClient, "\n"); +} + +void printDiskStatUsedInfo(const char* cmd) +{ + fprintf(CurrentClient, "Used Blocks\t0\t-\tBlocks\n"); +} + +void printDiskStatFree(const char* cmd) +{ + DiskInfo* disk_info; + char *mntpnt = (char *)getMntPnt(cmd); + + for (disk_info = first_ctnr(DiskStatList); disk_info; disk_info = next_ctnr(DiskStatList)) { + if (!strcmp(mntpnt, disk_info->mntpnt)) { + fprintf(CurrentClient, "%ld\n", disk_info->bfree); + } + } + + fprintf(CurrentClient, "\n"); +} + +void printDiskStatFreeInfo(const char* cmd) +{ + fprintf(CurrentClient, "Free Blocks\t0\t-\tBlocks\n"); +} + +void printDiskStatPercent(const char* cmd) +{ + DiskInfo* disk_info; + char *mntpnt = (char *)getMntPnt(cmd); + + for (disk_info = first_ctnr(DiskStatList); disk_info; disk_info = next_ctnr(DiskStatList)) { + if (!strcmp(mntpnt, disk_info->mntpnt)) { + fprintf(CurrentClient, "%d\n", disk_info->bused_percent); + } + } + + fprintf(CurrentClient, "\n"); +} + +void printDiskStatPercentInfo(const char* cmd) +{ + fprintf(CurrentClient, "Used Blocks\t0\t100\t%%\n"); +} diff --git a/ksysguard/ksysguardd/NetBSD/diskstat.h b/ksysguard/ksysguardd/NetBSD/diskstat.h new file mode 100644 index 000000000..06f247837 --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/diskstat.h @@ -0,0 +1,40 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 _diskstat_h_ +#define _diskstat_h_ + +void initDiskStat(struct SensorModul* sm); +void exitDiskStat(void); + +int updateDiskStat(void); +void checkDiskStat(void); + +void printDiskStat(const char* cmd); +void printDiskStatInfo(const char* cmd); + +void printDiskStatUsed(const char* cmd); +void printDiskStatUsedInfo(const char* cmd); +void printDiskStatFree(const char* cmd); +void printDiskStatFreeInfo(const char* cmd); +void printDiskStatPercent(const char* cmd); +void printDiskStatPercentInfo(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/NetBSD/loadavg.c b/ksysguard/ksysguardd/NetBSD/loadavg.c new file mode 100644 index 000000000..53eb9fc4e --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/loadavg.c @@ -0,0 +1,96 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdio.h> +#include <stdlib.h> + +#include "Command.h" +#include "ksysguardd.h" +#include "loadavg.h" + +static double LoadAvg[3]; + +/* +================================ public part ================================= +*/ + +void +initLoadAvg(struct SensorModul* sm) +{ + if (updateLoadAvg() < 0) + return; + + registerMonitor("cpu/loadavg1", "float", printLoadAvg1, + printLoadAvg1Info, sm); + registerMonitor("cpu/loadavg5", "float", printLoadAvg5, + printLoadAvg5Info, sm); + registerMonitor("cpu/loadavg15", "float", printLoadAvg15, + printLoadAvg15Info, sm); +} + +void +exitLoadAvg(void) +{ + removeMonitor("cpu/loadavg1"); + removeMonitor("cpu/loadavg5"); + removeMonitor("cpu/loadavg15"); +} + +int +updateLoadAvg(void) +{ + return getloadavg(LoadAvg, 3); +} + +void +printLoadAvg1(const char* c) +{ + fprintf(CurrentClient, "%f\n", LoadAvg[0]); +} + +void +printLoadAvg1Info(const char* c) +{ + fprintf(CurrentClient, "Load average 1 min\t0\t0\t\n"); +} + +void +printLoadAvg5(const char* c) +{ + fprintf(CurrentClient, "%f\n", LoadAvg[1]); +} + +void +printLoadAvg5Info(const char* c) +{ + fprintf(CurrentClient, "Load average 5 min\t0\t0\t\n"); +} + +void +printLoadAvg15(const char* c) +{ + fprintf(CurrentClient, "%f\n", LoadAvg[2]); +} + +void +printLoadAvg15Info(const char* c) +{ + fprintf(CurrentClient, "Load average 15 min\t0\t0\t\n"); +} diff --git a/ksysguard/ksysguardd/NetBSD/loadavg.h b/ksysguard/ksysguardd/NetBSD/loadavg.h new file mode 100644 index 000000000..801e4ef8d --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/loadavg.h @@ -0,0 +1,36 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 _loadavg_h_ +#define _loadavg_h_ + +void initLoadAvg(struct SensorModul* sm); +void exitLoadAvg(void); + +int updateLoadAvg(void); + +void printLoadAvg1(const char*); +void printLoadAvg1Info(const char*); +void printLoadAvg5(const char*); +void printLoadAvg5Info(const char*); +void printLoadAvg15(const char*); +void printLoadAvg15Info(const char*); + +#endif diff --git a/ksysguard/ksysguardd/NetBSD/logfile.c b/ksysguard/ksysguardd/NetBSD/logfile.c new file mode 100644 index 000000000..3b07ad8ac --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/logfile.c @@ -0,0 +1,175 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "Command.h" +#include "ccont.h" +#include "conf.h" +#include "ksysguardd.h" +#include "logfile.h" + +static CONTAINER LogFiles = 0; +static unsigned long counter = 1; + +typedef struct { + char name[256]; + FILE* fh; + unsigned long id; +} LogFileEntry; + +extern CONTAINER LogFileList; + +/* +================================ public part ================================= +*/ + +void initLogFile(struct SensorModul* sm) +{ + char monitor[1024]; + ConfigLogFile *entry; + + registerCommand("logfile_register", registerLogFile); + registerCommand("logfile_unregister", unregisterLogFile); + registerCommand("logfile_registered", printRegistered); + + for (entry = first_ctnr(LogFileList); entry; entry = next_ctnr(LogFileList)) + { + FILE* fp; + + /* register the log file if we can actually read the file. */ + if ((fp = fopen(entry->path, "r")) != NULL) + { + fclose(fp); + snprintf(monitor, 1024, "logfiles/%s", entry->name); + registerMonitor(monitor, "logfile", printLogFile, + printLogFileInfo, sm); + } + } + + LogFiles = new_ctnr(); +} + +void exitLogFile(void) +{ + destr_ctnr(LogFiles, free); +} + +void printLogFile(const char* cmd) +{ + char line[1024]; + unsigned long id; + int i; + char ch; + LogFileEntry *entry; + + sscanf(cmd, "%*s %lu", &id); + + for (entry = first_ctnr(LogFiles); entry; entry = next_ctnr(LogFiles)) { + if (entry->id == id) { + while (fgets(line, sizeof(line), entry->fh) != NULL) { + fprintf(CurrentClient, "%s", line); + } + clearerr(entry->fh); + } + } + + fprintf(CurrentClient, "\n"); +} + +void printLogFileInfo(const char* cmd) +{ + fprintf(CurrentClient, "LogFile\n"); +} + +void registerLogFile(const char* cmd) +{ + char name[257]; + FILE* file; + LogFileEntry *entry; + ConfigLogFile *conf; + + memset(name, 0, sizeof(name)); + sscanf(cmd, "%*s %256s", name); + + for (conf = first_ctnr(LogFileList); conf; conf = next_ctnr(LogFileList)) { + if (!strcmp(conf->name, name)) { + if ((file = fopen(conf->path, "r")) == NULL) { + print_error("fopen()"); + fprintf(CurrentClient, "0\n"); + return; + } + + fseek(file, 0, SEEK_END); + + if ((entry = (LogFileEntry *)malloc(sizeof(LogFileEntry))) == NULL) { + print_error("malloc()"); + fprintf(CurrentClient, "0\n"); + return; + } + + entry->fh = file; + strlcpy(entry->name, conf->name, sizeof(entry->name)); + entry->id = counter; + + push_ctnr(LogFiles, entry); + + fprintf(CurrentClient, "%lu\n", counter); + counter++; + + return; + } + } + + fprintf(CurrentClient, "0\n"); +} + +void unregisterLogFile(const char* cmd) +{ + unsigned long id; + LogFileEntry *entry; + + sscanf(cmd, "%*s %lu", &id); + + for (entry = first_ctnr(LogFiles); entry; entry = next_ctnr(LogFiles)) { + if (entry->id == id) { + fclose(entry->fh); + free(remove_ctnr(LogFiles)); + fprintf(CurrentClient, "\n"); + return; + } + } + + fprintf(CurrentClient, "\n"); +} + +void printRegistered(const char* cmd) +{ + LogFileEntry *entry; + + for (entry = first_ctnr(LogFiles); entry; entry = next_ctnr(LogFiles)) + fprintf(CurrentClient, "%s:%lu\n", entry->name, entry->id); + + fprintf(CurrentClient, "\n"); +} diff --git a/ksysguard/ksysguardd/NetBSD/logfile.h b/ksysguard/ksysguardd/NetBSD/logfile.h new file mode 100644 index 000000000..45ade9013 --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/logfile.h @@ -0,0 +1,36 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 _logfile_h_ +#define _logfile_h_ + +void initLogFile(struct SensorModul* sm); +void exitLogFile(void); + +void printLogFile(const char* cmd); +void printLogFileInfo(const char* cmd); + +void registerLogFile(const char* cmd); +void unregisterLogFile(const char* cmd); + +/* debug command */ +void printRegistered(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/NetBSD/netdev.c b/ksysguard/ksysguardd/NetBSD/netdev.c new file mode 100644 index 000000000..477acc40e --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/netdev.c @@ -0,0 +1,304 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <sys/types.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/socket.h> + +#include <net/route.h> +#include <net/if.h> +#include <net/if_dl.h> + +#include <ifaddrs.h> +#include <stdlib.h> +#include <string.h> + +#include "Command.h" +#include "ksysguardd.h" +#include "netdev.h" + + +#define I_bytes 0 +#define I_packs 1 +#define I_errs 2 +#define I_mcasts 3 +#define I_lost 4 + +typedef struct { + char name[32]; + u_long recv[5], Drecv[5], sent[5], Dsent[5]; +} NetDevInfo; + +#define LEN(X) (sizeof(X)/sizeof(X[0])) + +#define MAXNETDEVS 64 +static NetDevInfo NetDevs[MAXNETDEVS], newval[MAXNETDEVS]; +static int NetDevCnt = 0; +static struct SensorModul *NetDevSM; + +/* Read the system's traffic registers. + * Merely count the IFs if countp nonzero. + * Returns count of IFs read, or -1; the data are written into newval. + * Based on getifaddrs source; getifaddrs itself seems to + * compile incorrectly, omitting the traffic data. (It also + * does things this doesn't need, thus this is slightly more efficient.) + */ +static int readSys(int countp) +{ + size_t len; + char *bfr, *ptr; + struct rt_msghdr *rtm; + NetDevInfo *nv; + static int mib[] = { + /* see sysctl(3): */ + CTL_NET, + PF_ROUTE, + 0, /* `currently always 0' */ + 0, /* `may be set to 0 to select all address families' */ + NET_RT_IFLIST, + 0 /* ignored but six levels are needed */ + }; + + if (-1==sysctl(mib, LEN(mib), NULL, &len, NULL, 0)) + return -1; + if (!(bfr = malloc(len))) + return -1; + if (-1==sysctl(mib, LEN(mib), bfr, &len, NULL, 0)) { + free(bfr); + return -1; + } + nv = newval; + for (ptr=bfr; ptr<bfr+len; ptr+=rtm->rtm_msglen) { + struct if_msghdr *ifm; + + rtm = (void*)ptr; /* chg ptr type to router msg */ + + if (rtm->rtm_version != RTM_VERSION) { + continue; + } + + if (rtm->rtm_type != RTM_IFINFO) { + continue; + } + + ifm = (void*)rtm; /* chg ptr type to interface msg */ + if (!(ifm->ifm_flags & IFF_UP)) { + continue; + } + + if (!countp) { + /* a sdl is concat'd to the if msg */ + struct sockaddr_dl *sdl = (void*)(ifm+1); + + /* copy and terminate the name */ + /*fixme: check for overruns */ + memcpy(nv->name, sdl->sdl_data, sdl->sdl_nlen); + nv->name[sdl->sdl_nlen] = 0; + + /* copy the data */ + nv->recv[I_bytes] = ifm->ifm_data.ifi_ibytes; + nv->recv[I_packs] = ifm->ifm_data.ifi_ipackets; + nv->recv[I_errs] = ifm->ifm_data.ifi_ierrors; + nv->recv[I_mcasts] = ifm->ifm_data.ifi_imcasts; + nv->recv[I_lost] = ifm->ifm_data.ifi_iqdrops; + nv->sent[I_bytes] = ifm->ifm_data.ifi_obytes; + nv->sent[I_packs] = ifm->ifm_data.ifi_opackets; + nv->sent[I_errs] = ifm->ifm_data.ifi_oerrors; + nv->sent[I_mcasts] = ifm->ifm_data.ifi_omcasts; + nv->sent[I_lost] = ifm->ifm_data.ifi_collisions; + } + + /*fixme: guard against buffer overrun */ + nv++; + } + free(bfr); + return nv-newval; +} + + +/* ------------------------------ public part --------------------------- */ + +static void prVal(const char*, int); +void printNetDevRecv(const char *cmd) { prVal(cmd,0); } +void printNetDevSent(const char *cmd) { prVal(cmd,1); } + +static void prInfo(const char*, int); +void printNetDevRecvInfo(const char *cmd) { prInfo(cmd,0); } +void printNetDevSentInfo(const char *cmd) { prInfo(cmd,1); } + +static struct { + char *label; + cmdExecutor read, inform; + struct { + char *label, *info; + int index; + } op[5]; +} opTable[] = { + {"receiver", + printNetDevRecv, printNetDevRecvInfo, + {{"data", "Received Data\t0\t0\tB/s\n", I_bytes}, + {"packets", "Received Packets\t0\t0\tHz\n", I_packs}, + {"errors", "Receiver Errors\t0\t0\tHz\n", I_errs}, + {"multicast", "Received Multicast Packets\t0\t0\tHz\n", I_mcasts}, + {"drops", "Receiver Drops\t0\t0\tHz\n", I_lost}}}, + {"transmitter", + printNetDevSent, printNetDevSentInfo, + {{"data", "Sent Data\t0\t0\tB/s\n", I_bytes}, + {"packets", "Sent Packets\t0\t0\tHz\n", I_packs}, + {"errors", "Transmitter Errors\t0\t0\tHz\n", I_errs}, + {"multicast", "Sent Multicast Packets\t0\t0\tHz\n", I_mcasts}, + {"collisions", "Transmitter Collisions\t0\t0\tHz\n", I_lost}}} +}; + + +static void prVal(const char *cmd, int N) { + char *p, *q, *r; + int i, d; + + if (!(p=rindex(cmd, '/'))) + return; + *p=0; + q=rindex(cmd, '/'); + *q=0; + r=rindex(cmd, '/'); + r++; + for (d=NetDevCnt; d--; ) + if (!strcmp(r, NetDevs[d].name)) + break; + *q=*p='/'; + + if (-1 == d) return; + + p++; + for (i=0; i<LEN(opTable[0].op); i++) + if (!strcmp(p, opTable[N].op[i].label)) + fprintf(CurrentClient, "%lu", + /*fixme: ugly and presumptuous */ + (N?NetDevs[d].Dsent:NetDevs[d].Drecv)[opTable[N].op[i].index]); + fprintf(CurrentClient, "\n"); +} + + +static void prInfo(const char *cmd, int N) { + char *p, *q; + int i; + + if (!(p=rindex(cmd, '/'))) return; + p++; + + q = p+strlen(p)-1; + if ('?' != *q) return; + *q=0; + + for (i=0; i<LEN(opTable[0].op); i++) + if (!strcmp(p, opTable[N].op[i].label)) + fputs(opTable[N].op[i].info, CurrentClient); + *q='?'; +} + + + +static void NDreg (int setp) +{ + int i; + + for (i = 0; i<NetDevCnt; i++) { + int j; + + for (j=0; j<LEN(opTable); j++) { + int k; + + for (k=0; k<LEN(opTable[0].op); k++) { + char buffer[1024]; + + snprintf(buffer, sizeof(buffer), + "network/interfaces/%s/%s/%s", + NetDevs[i].name, + opTable[j].label, + opTable[j].op[k].label); + + /* printf("%d %d %d %s\n",i,j,k,buffer); */ + + if (setp) + registerMonitor(buffer, + "integer", + opTable[j].read, + opTable[j].inform, NetDevSM); + else + removeMonitor(buffer); + } + + } + } +} + +void initNetDev(struct SensorModul* sm) { + int i; + + NetDevSM = sm; + + updateNetDev(); + + for (i=LEN(NetDevs); i--;) { + strcpy(NetDevs[i].name, newval[i].name); + } + + NDreg(!0); +} + + +void exitNetDev(void) { + NDreg(0); +} + +void updateNetDev(void) { + NetDevInfo *p, *q; + int n; + + if (-1==(n = readSys(0))) + return; + + NetDevCnt = n; + /*fixme: assumes the interfaces are in the same order each time */ + for (p=NetDevs, q=newval; n--; p++, q++) { + int i; + /* calculate deltas */ + for (i=0; i<5; i++) { + p->Drecv[i] = q->recv[i]-p->recv[i]; + p->recv[i] = q->recv[i]; + p->Dsent[i] = q->sent[i]-p->sent[i]; + p->sent[i] = q->sent[i]; + + } + } +} + +void checkNetDev(void) { + if (readSys(!0) != NetDevCnt) { + /* interface has been added or removed + so we do a reset */ + exitNetDev(); + initNetDev(NetDevSM); + } +} + + +/* eof */ diff --git a/ksysguard/ksysguardd/NetBSD/netdev.h b/ksysguard/ksysguardd/NetBSD/netdev.h new file mode 100644 index 000000000..4287c9203 --- /dev/null +++ b/ksysguard/ksysguardd/NetBSD/netdev.h @@ -0,0 +1,35 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 _netdev_h_ +#define _netdev_h_ + +void initNetDev(struct SensorModul* sm); +void exitNetDev(void); + +void updateNetDev(void); +void checkNetDev(void); + +void printNetDevRecBytes(const char* cmd); +void printNetDevRecBytesInfo(const char* cmd); +void printNetDevSentBytes(const char* cmd); +void printNetDevSentBytesInfo(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/OpenBSD/Makefile.am b/ksysguard/ksysguardd/OpenBSD/Makefile.am new file mode 100644 index 000000000..78d97e293 --- /dev/null +++ b/ksysguard/ksysguardd/OpenBSD/Makefile.am @@ -0,0 +1,6 @@ +AM_CFLAGS = -Wall + +INCLUDES = -I$(srcdir)/../../CContLib -I$(srcdir)/.. + +noinst_LIBRARIES = libksysguardd.a +libksysguardd_a_SOURCES = cpu.c memory.c diff --git a/ksysguard/ksysguardd/OpenBSD/cpu.c b/ksysguard/ksysguardd/OpenBSD/cpu.c new file mode 100644 index 000000000..3d1535ffe --- /dev/null +++ b/ksysguard/ksysguardd/OpenBSD/cpu.c @@ -0,0 +1,209 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@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 <sys/param.h> +#include <sys/sysctl.h> +#include <sys/dkstat.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "cpu.h" +#include "Command.h" +#include "ksysguardd.h" + +long percentages(int cnt, int *out, long *new, long *old, long *diffs); + +unsigned long cp_time_offset; + +long cp_time[CPUSTATES]; +long cp_old[CPUSTATES]; +long cp_diff[CPUSTATES]; +int cpu_states[CPUSTATES]; + +void +initCpuInfo(struct SensorModul* sm) +{ + /* Total CPU load */ + registerMonitor("cpu/user", "integer", printCPUUser, + printCPUUserInfo, sm); + registerMonitor("cpu/nice", "integer", printCPUNice, + printCPUNiceInfo, sm); + registerMonitor("cpu/sys", "integer", printCPUSys, + printCPUSysInfo, sm); + registerMonitor("cpu/idle", "integer", printCPUIdle, + printCPUIdleInfo, sm); + registerMonitor("cpu/interrupt", "integer", printCPUInterrupt, + printCPUInterruptInfo, sm); + + updateCpuInfo(); +} + +void +exitCpuInfo(void) +{ +} + +int +updateCpuInfo(void) +{ + static int cp_time_mib[] = {CTL_KERN, KERN_CPTIME}; + size_t size; + size=sizeof(cp_time); + sysctl(cp_time_mib, 2, &cp_time, &size, NULL, 0); + percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); + return (0); +} + +void +printCPUUser(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", cpu_states[CP_USER]/10); +} + +void +printCPUUserInfo(const char* cmd) +{ + fprintf(CurrentClient, "CPU User Load\t0\t100\t%%\n"); +} + +void +printCPUNice(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", cpu_states[CP_NICE]/10); +} + +void +printCPUNiceInfo(const char* cmd) +{ + fprintf(CurrentClient, "CPU Nice Load\t0\t100\t%%\n"); +} + +void +printCPUSys(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", cpu_states[CP_SYS]/10); +} + +void +printCPUSysInfo(const char* cmd) +{ + fprintf(CurrentClient, "CPU System Load\t0\t100\t%%\n"); +} + +void +printCPUIdle(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", cpu_states[CP_IDLE]/10); +} + +void +printCPUIdleInfo(const char* cmd) +{ + fprintf(CurrentClient, "CPU Idle Load\t0\t100\t%%\n"); +} + +void +printCPUInterrupt(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", cpu_states[CP_INTR]/10); +} + +void +printCPUInterruptInfo(const char* cmd) +{ + fprintf(CurrentClient, "CPU Interrupt Load\t0\t100\t%%\n"); +} + +/* The part ripped from top... */ +/* + * Top users/processes display for Unix + * Version 3 + * + * This program may be freely redistributed, + * but this entire comment MUST remain intact. + * + * Copyright (c) 1984, 1989, William LeFebvre, Rice University + * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University + */ + +/* + * percentages(cnt, out, new, old, diffs) - calculate percentage change + * between array "old" and "new", putting the percentages i "out". + * "cnt" is size of each array and "diffs" is used for scratch space. + * The array "old" is updated on each call. + * The routine assumes modulo arithmetic. This function is especially + * useful on BSD mchines for calculating cpu state percentages. + */ + +long percentages(cnt, out, new, old, diffs) + +int cnt; +int *out; +register long *new; +register long *old; +long *diffs; + +{ + register int i; + register long change; + register long total_change; + register long *dp; + long half_total; + + /* initialization */ + total_change = 0; + dp = diffs; + + /* calculate changes for each state and the overall change */ + for (i = 0; i < cnt; i++) + { + if ((change = *new - *old) < 0) + { + /* this only happens when the counter wraps */ + change = (int) + ((unsigned long)*new-(unsigned long)*old); + } + total_change += (*dp++ = change); + *old++ = *new++; + } + + /* avoid divide by zero potential */ + if (total_change == 0) + { + total_change = 1; + } + + /* calculate percentages based on overall change, rounding up */ + half_total = total_change / 2l; + + /* Do not divide by 0. Causes Floating point exception */ + if(total_change) { + for (i = 0; i < cnt; i++) + { + *out++ = (int)((*diffs++ * 1000 + half_total) / total_change); + } + } + + /* return the total in case the caller wants to use it */ + return(total_change); +} diff --git a/ksysguard/ksysguardd/OpenBSD/cpu.h b/ksysguard/ksysguardd/OpenBSD/cpu.h new file mode 100644 index 000000000..a1188cd82 --- /dev/null +++ b/ksysguard/ksysguardd/OpenBSD/cpu.h @@ -0,0 +1,51 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@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 _cpuinfo_h_ +#define _cpuinfo_h_ + +struct SensorModul; + +void initCpuInfo(struct SensorModul* sm); +void exitCpuInfo(void); + +int updateCpuInfo(void); + +void printCPUUser(const char* cmd); +void printCPUUserInfo(const char* cmd); +void printCPUNice(const char* cmd); +void printCPUNiceInfo(const char* cmd); +void printCPUSys(const char* cmd); +void printCPUSysInfo(const char* cmd); +void printCPUIdle(const char* cmd); +void printCPUIdleInfo(const char* cmd); +void printCPUInterrupt(const char* cmd); +void printCPUInterruptInfo(const char* cmd); +void printCPUxUser(const char* cmd); +void printCPUxUserInfo(const char* cmd); +void printCPUxNice(const char* cmd); +void printCPUxNiceInfo(const char* cmd); +void printCPUxSys(const char* cmd); +void printCPUxSysInfo(const char* cmd); +void printCPUxIdle(const char* cmd); +void printCPUxIdleInfo(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/OpenBSD/memory.c b/ksysguard/ksysguardd/OpenBSD/memory.c new file mode 100644 index 000000000..aaf893268 --- /dev/null +++ b/ksysguard/ksysguardd/OpenBSD/memory.c @@ -0,0 +1,207 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@kde.org> + Copyright (c) 1999-2000 Hans Petter Bieker <bieker@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 <sys/param.h> +#include <sys/sysctl.h> +#include <sys/dkstat.h> +#include <sys/swap.h> + +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "Command.h" +#include "memory.h" +#include "ksysguardd.h" + +static size_t Total = 0; +static size_t MFree = 0; +static size_t Active = 0; +static size_t InActive = 0; +static size_t STotal = 0; +static size_t SFree = 0; +static size_t SUsed = 0; +static int pageshift = 0; + +/* define pagetok in terms of pageshift */ +#define pagetok(size) ((size) << pageshift) + +void swapmode(int *used, int *total); + +void +initMemory(struct SensorModul* sm) +{ + int pagesize; + static int physmem_mib[] = { CTL_HW, HW_PHYSMEM }; + size_t size; + /* get the page size with "getpagesize" and calculate pageshift from + * it */ + pagesize = getpagesize(); + pageshift = 0; + while (pagesize > 1) { + pageshift++; + pagesize >>= 1; + } + size = sizeof(Total); + sysctl(physmem_mib, 2, &Total, &size, NULL, 0); + Total /= 1024; + swapmode(&SUsed, &STotal); + + registerMonitor("mem/physical/free", "integer", printMFree, printMFreeInfo, sm); + registerMonitor("mem/physical/active", "integer", printActive, printActiveInfo, sm); + registerMonitor("mem/physical/inactive", "integer", printInActive, printInActiveInfo, sm); + registerMonitor("mem/swap/free", "integer", printSwapFree, printSwapFreeInfo, sm); + registerMonitor("mem/swap/used", "integer", printSwapUsed, printSwapUsedInfo, sm); +} + +void +exitMemory(void) +{ +} + +int +updateMemory(void) +{ + static int vmtotal_mib[] = {CTL_VM, VM_METER}; + size_t size; + struct vmtotal vmtotal; + size = sizeof(vmtotal); + + if (sysctl(vmtotal_mib, 2, &vmtotal, &size, NULL, 0) < 0) + return -1; + + MFree = pagetok(vmtotal.t_free); + MFree /= 1024; + Active = pagetok(vmtotal.t_arm); + Active /= 1024; + InActive = pagetok(vmtotal.t_rm); + InActive /= 1024; + InActive -= Active; + + swapmode(&SUsed, &STotal); + SFree = STotal - SUsed; + return 0; +} + +void +printMFree(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", MFree); +} + +void +printMFreeInfo(const char* cmd) +{ + fprintf(CurrentClient, "Free Memory\t0\t%d\tKB\n", Total); +} + +void +printActive(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", Active); +} + +void +printActiveInfo(const char* cmd) +{ + fprintf(CurrentClient, "Active Memory\t0\t%d\tKB\n", Total); +} + +void +printInActive(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", InActive); +} + +void +printInActiveInfo(const char* cmd) +{ + fprintf(CurrentClient, "InActive Memory\t0\t%d\tKB\n", Total); +} + +void +printSwapUsed(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", SUsed); +} + +void +printSwapUsedInfo(const char* cmd) +{ + fprintf(CurrentClient, "Used Swap Memory\t0\t%d\tKB\n", STotal); +} + +void +printSwapFree(const char* cmd) +{ + fprintf(CurrentClient, "%d\n", SFree); +} + +void +printSwapFreeInfo(const char* cmd) +{ + fprintf(CurrentClient, "Free Swap Memory\t0\t%d\tKB\n", STotal); +} + +/* +This function swapmode was originally written by Tobias +Weingartner <weingart@openbsd.org> + +Taken from OpenBSD top command +*/ +void +swapmode (int *used, int *total) +{ + int nswap, rnswap, i; + struct swapent *swdev; + + *total = *used = 0; + + /* Number of swap devices */ + nswap = swapctl(SWAP_NSWAP, 0, 0); + if (nswap == 0) + return; + + swdev = (struct swapent *) malloc(nswap * sizeof(*swdev)); + if (swdev == NULL) + return; + + rnswap = swapctl(SWAP_STATS, swdev, nswap); + if (rnswap == -1) { + free(swdev); + return; + } + + /* if rnswap != nswap, then what? */ + + /* Total things up */ + for (i = 0; i < nswap; i++) { + if (swdev[i].se_flags & SWF_ENABLE) { + *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE)); + *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE)); + } + } + + free(swdev); +} diff --git a/ksysguard/ksysguardd/OpenBSD/memory.h b/ksysguard/ksysguardd/OpenBSD/memory.h new file mode 100644 index 000000000..9cb11373a --- /dev/null +++ b/ksysguard/ksysguardd/OpenBSD/memory.h @@ -0,0 +1,43 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@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 _memory_h_ +#define _memory_h_ + +struct SensorModul; + +void initMemory(struct SensorModul* sm); +void exitMemory(void); + +int updateMemory(void); + +void printMFree(const char* cmd); +void printMFreeInfo(const char* cmd); +void printActive(const char* cmd); +void printActiveInfo(const char* cmd); +void printInActive(const char* cmd); +void printInActiveInfo(const char* cmd); +void printSwapUsed(const char* cmd); +void printSwapUsedInfo(const char* cmd); +void printSwapFree(const char* cmd); +void printSwapFreeInfo(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/PWUIDCache.c b/ksysguard/ksysguardd/PWUIDCache.c new file mode 100644 index 000000000..b0140e0a7 --- /dev/null +++ b/ksysguard/ksysguardd/PWUIDCache.c @@ -0,0 +1,114 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <pwd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <time.h> + +#include "ccont.h" + +#include "PWUIDCache.h" + +/* Cached values become invalid after 5 minutes */ +#define TIMEOUT 300 + +typedef struct { + uid_t uid; + char* uName; + time_t tStamp; +} CachedPWUID; + +static CONTAINER UIDCache = 0; +static time_t lastCleanup = 0; + +void PWUIDCache_cleanup( void* c ); + +static int uidCmp( void* p1, void* p2 ) +{ + return ( ((CachedPWUID*)p1)->uid - ((CachedPWUID*)p2)->uid ); +} + +void PWUIDCache_cleanup( void* c ) +{ + if ( c ) { + if ( ((CachedPWUID*)c)->uName ) + free ( ((CachedPWUID*)c)->uName ); + free ( c ); + } +} + +void initPWUIDCache() +{ + UIDCache = new_ctnr(); +} + +void exitPWUIDCache() +{ + destr_ctnr( UIDCache, PWUIDCache_cleanup ); +} + +const char* getCachedPWUID( uid_t uid ) +{ + CachedPWUID key; + CachedPWUID* entry = 0; + long idx; + time_t stamp; + + stamp = time( 0 ); + if ( stamp - lastCleanup > TIMEOUT ) { + /* Cleanup cache entries every TIMEOUT seconds so that we + * don't pile tons of unused entries, and to make sure that + * our entries are not outdated. */ + for ( entry = first_ctnr( UIDCache ); entry; entry = next_ctnr( UIDCache ) ) { + /* If a cache entry has not been updated for TIMEOUT + * seconds the entry is removed. */ + if ( stamp - entry->tStamp > TIMEOUT ) + PWUIDCache_cleanup( remove_ctnr( UIDCache ) ); + } + + lastCleanup = stamp; + } + + key.uid = uid; + if ( ( idx = search_ctnr( UIDCache, uidCmp, &key ) ) < 0 ) { + struct passwd* pwent; + + /* User id is not yet known */ + entry = (CachedPWUID*)malloc( sizeof( CachedPWUID ) ); + entry->tStamp = stamp; + entry->uid = uid; + + pwent = getpwuid( uid ); + if ( pwent ) + entry->uName = strdup( pwent->pw_name ); + else + entry->uName = strdup( "?" ); + + push_ctnr( UIDCache, entry ); + bsort_ctnr( UIDCache, uidCmp ); + } else { + /* User is is already known */ + entry = get_ctnr( UIDCache, idx ); + } + + return entry->uName; +} diff --git a/ksysguard/ksysguardd/PWUIDCache.h b/ksysguard/ksysguardd/PWUIDCache.h new file mode 100644 index 000000000..ce28df0fc --- /dev/null +++ b/ksysguard/ksysguardd/PWUIDCache.h @@ -0,0 +1,36 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2000 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <sys/types.h> + +#ifndef KSG_PWUIDCACHE_H +#define KSG_PWUIDCACHE_H + +/** + getpwuid() can be fairly expensive on NIS or LDAP systems that do not + use chaching. This module implements a cache for uid to user name + mappings. + */ +void initPWUIDCache( void ); +void exitPWUIDCache( void ); + +const char* getCachedPWUID( uid_t uid ); + +#endif diff --git a/ksysguard/ksysguardd/Porting-HOWTO b/ksysguard/ksysguardd/Porting-HOWTO new file mode 100644 index 000000000..4576783bc --- /dev/null +++ b/ksysguard/ksysguardd/Porting-HOWTO @@ -0,0 +1,133 @@ +This document describes the interface between ksysguard and +ksysguardd. ksysguardd is started as a child of ksysguard, either +directly or via a shell. Alternatively a ksysguardd can listen on a +port and a single instance can then be used by multiple instances of +ksysguard. + +This client/server design was chosen, because on some operating +systems the back-end needs elevated permissions. Since C++ programs +should NEVER have setgid/setuid permissions, a plain C back-end was +needed. It also allowed for an easy network support using existing +security mechanisms (ssh). + +ksysguard sends commands and ksysguardd answers to them. Each answer +ends with the string "\nksysguardd> ". Error messages are enclosed in +ESC '\033' characters. Therefor regular messages may never contain +ESC. The set of commands that each ksysguardd implementation supports +can be very different. There are only a very few mandatory command and +a few recommended commands. + +The mandatory commands are 'monitors', 'test' and 'quit'. +The recommended commands are: + +cpu/idle +cpu/sys +cpu/nice +cpu/user +mem/swap/free +mem/swap/used +mem/physical/cached +mem/physical/buf +mem/physical/application +mem/physical/used +mem/physical/free +ps +pscount + +Without these commands KSysGuard is not very helpful. + +The 'monitors' command returns the list of available sensors. The +output looks like this: + +-------- +mem/physical/free integer +ps table +pscount integer +ksysguardd> +-------- + +Sensor names can be hierarchical. Each level is separated by a +/. ksysguard uses a tree widget in the SensorBrowser to display the +commands in a tree. Every sensor name must be followed by the type of +the sensor separated by a tab. Currently 4 different types of sensors +are supported, integer, float, listview and table. The table sensor +returns the information for the ProcessController widget. listview +sensors use a generic table to display information. To find out more +about a sensor an additional command must be implemented for each +sensor that has a questionmark appended to the sensor name. It can be +used to find out more about the sensor. + +-------- +ksysguardd> mem/physical/free? +Free Memory 0 260708 KB +ksysguardd> +-------- + +integer and float sensor return a short description, the minimum and +maximum value and the unit. All fields are again separated by +tabs. The minimum and maximum values can both be 0 to trigger the +auto-range feature of the display. + +-------- +ksysguardd> ps? +Name PID PPID UID GID Status User% System% Nice VmSize VmRss VmLib Login Command +s d d d d S f f d d sksysguardd> +-------- + +This is the output of the ps? inquiry command. The ps command is the +only recommended command. The answer to ps? consists of 2 lines. Both +lines have the same number of fields each separated by a tab. The +first line specifies the name of the columns and the second the type +of the values in the column. + +d: integer value +D: integer value that should be localized in the frontend +f: floating point value +s: string value +S: string value that needs to be translated + Strings must be added to the ProcessList::columnDict dictionary. + +For the ProcessController to function properly the Name and PID +columns are mandatory. All other columns are optional and their +content may be implementation dependant. It is highly recommended not +to deviate from the Linux implementation unless absolutely +unavoidable, in order to provide a consistent interface across all +platforms. + +The 'test' command can be used by the front-end to find out if a +certain other command is supported by this version of ksysguardd. The +command returns "1\n" if the command is supported and "0\n" if the +command is not supported. + +The 'quit' command terminates ksysguardd. + +ksysguardd may support dynamic monitor sets. If a CPU is added or an +interface disabled, monitors may be added or removed. To notify the +front-end about this, you need to send the string "RECONFIGURE\n" over +stderr. This causes the front-end to request the list of monitors +again and adapt it's layout accordingly. If ksysguardd receives a +command it doesn't know it has to reply with "UNKNOWN +COMMAND\nksysguardd> ". + +ksysguardd does not handle native language support. In order to have a +minimum installation (only a single file) on the monitored machine, +all translation are handled by the front-end. Please see the files +gui/ksgrd/SensorManger.cc and gui/SensorDisplayLib/ProcessTable.cc +if you add new strings. + +/** + * Since I'm very much a C++ guy I've written some functions which + * provide a similar functionality as template classes for lists and + * arrays. The Linux implementation uses them. Feel free to use them for + * the ports as well if you like. The interface is described in + * CContLib/ccont.h. Unfortunately I still haven't found time to document + * it properly, but the use should be fairly obvious. + */ + +Chris <cs@kde.org> + +Since the above mentioned CContLib was a little slow I reimplement it and +wrote some docu stuff in the header file. If you need an example for use +look at ksysguardd/Linux/diskstat.(h|c). + +Tobias <tokoe@kde.org> diff --git a/ksysguard/ksysguardd/Solaris/LoadAvg.c b/ksysguard/ksysguardd/Solaris/LoadAvg.c new file mode 100644 index 000000000..aea38a212 --- /dev/null +++ b/ksysguard/ksysguardd/Solaris/LoadAvg.c @@ -0,0 +1,120 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> + +#include "config.h" + +#ifdef HAVE_KSTAT +#include <kstat.h> +#endif + +#include "ksysguardd.h" +#include "Command.h" +#include "LoadAvg.h" + +double loadavg1 = 0.0; +double loadavg5 = 0.0; +double loadavg15 = 0.0; + +void initLoadAvg( struct SensorModul* sm ) { +#ifdef HAVE_KSTAT + registerMonitor( "cpu/loadavg1", "float", + printLoadAvg1, printLoadAvg1Info, sm ); + registerMonitor( "cpu/loadavg5", "float", + printLoadAvg5, printLoadAvg5Info, sm ); + registerMonitor( "cpu/loadavg15", "float", + printLoadAvg15, printLoadAvg15Info, sm ); +#endif +} + +void exitLoadAvg( void ) { +} + +int updateLoadAvg( void ) { + +#ifdef HAVE_KSTAT + kstat_ctl_t *kctl; + kstat_t *ksp; + kstat_named_t *kdata; + + /* + * get a kstat handle and update the user's kstat chain + */ + if( (kctl = kstat_open()) == NULL ) + return( 0 ); + while( kstat_chain_update( kctl ) != 0 ) + ; + + /* + * traverse the kstat chain to find the appropriate statistics + */ + if( (ksp = kstat_lookup( kctl, "unix", 0, "system_misc" )) == NULL ) + return( 0 ); + if( kstat_read( kctl, ksp, NULL ) == -1 ) + return( 0 ); + + /* + * lookup the data + */ + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "avenrun_1min" ); + if( kdata != NULL ) + loadavg1 = LOAD( kdata->value.ui32 ); + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "avenrun_5min" ); + if( kdata != NULL ) + loadavg5 = LOAD( kdata->value.ui32 ); + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "avenrun_15min" ); + if( kdata != NULL ) + loadavg15 = LOAD( kdata->value.ui32 ); + + kstat_close( kctl ); +#endif /* ! HAVE_KSTAT */ + + return( 0 ); +} + +void printLoadAvg1Info( const char *cmd ) { + fprintf(CurrentClient, "avnrun 1min\t0\t0\n" ); +} + +void printLoadAvg1( const char *cmd ) { + fprintf(CurrentClient, "%f\n", loadavg1 ); +} + +void printLoadAvg5Info( const char *cmd ) { + fprintf(CurrentClient, "avnrun 5min\t0\t0\n" ); +} + +void printLoadAvg5( const char *cmd ) { + fprintf(CurrentClient, "%f\n", loadavg5 ); +} + +void printLoadAvg15Info( const char *cmd ) { + fprintf(CurrentClient, "avnrun 15min\t0\t0\n" ); +} + +void printLoadAvg15( const char *cmd ) { + fprintf(CurrentClient, "%f\n", loadavg15 ); +} diff --git a/ksysguard/ksysguardd/Solaris/LoadAvg.h b/ksysguard/ksysguardd/Solaris/LoadAvg.h new file mode 100644 index 000000000..eea8ad82e --- /dev/null +++ b/ksysguard/ksysguardd/Solaris/LoadAvg.h @@ -0,0 +1,41 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@kde.org> + + Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + + 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 _LoadAvg_h_ +#define _LoadAvg_h_ + +#define LOAD(a) ((double)(a) / (1 << 8 )) + +void initLoadAvg(struct SensorModul* sm); +void exitLoadAvg(void); + +int updateLoadAvg(void); + +void printLoadAvg1( const char *cmd ); +void printLoadAvg1Info( const char *cmd ); +void printLoadAvg5( const char *cmd ); +void printLoadAvg5Info( const char *cmd ); +void printLoadAvg15( const char *cmd ); +void printLoadAvg15Info( const char *cmd ); + +#endif /* _LoadAvg_h_ */ diff --git a/ksysguard/ksysguardd/Solaris/Makefile.am b/ksysguard/ksysguardd/Solaris/Makefile.am new file mode 100644 index 000000000..f5dd51c96 --- /dev/null +++ b/ksysguard/ksysguardd/Solaris/Makefile.am @@ -0,0 +1,10 @@ +# +# + +# Sun's C++ compiler doesn't support -Wall +#AM_CFLAGS = -Wall + +INCLUDES = -I$(srcdir)/../../CContLib -I$(srcdir)/.. + +noinst_LIBRARIES = libksysguardd.a +libksysguardd_a_SOURCES = Memory.c LoadAvg.c ProcessList.c NetDev.c diff --git a/ksysguard/ksysguardd/Solaris/Memory.c b/ksysguard/ksysguardd/Solaris/Memory.c new file mode 100644 index 000000000..efc2f18ac --- /dev/null +++ b/ksysguard/ksysguardd/Solaris/Memory.c @@ -0,0 +1,223 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "config.h" + +/* Stop <sys/swap.h> from crapping out on 32-bit architectures. */ + +#if !defined(_LP64) && _FILE_OFFSET_BITS == 64 +# undef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 32 +#endif + +#include <sys/stat.h> +#include <sys/swap.h> +#include <vm/anon.h> + +#ifdef HAVE_KSTAT +#include <kstat.h> +#endif + +#include "ksysguardd.h" +#include "Command.h" +#include "Memory.h" + +static int Dirty = 1; +static t_memsize totalmem = (t_memsize) 0; +static t_memsize freemem = (t_memsize) 0; +static long totalswap = 0L; +static long freeswap = 0L; +static struct anoninfo am_swap; + +/* + * this is borrowed from top's m_sunos5 module + * used by permission from William LeFebvre + */ +static int pageshift; +static long (*p_pagetok) (); +#define pagetok(size) ((*p_pagetok)(size)) + +long pagetok_none( long size ) { + return( size ); +} + +long pagetok_left( long size ) { + return( size << pageshift ); +} + +long pagetok_right( long size ) { + return( size >> pageshift ); +} + +void initMemory( struct SensorModul* sm ) { + + long i = sysconf( _SC_PAGESIZE ); + + pageshift = 0; + while( (i >>= 1) > 0 ) + pageshift++; + + /* calculate an amount to shift to K values */ + /* remember that log base 2 of 1024 is 10 (i.e.: 2^10 = 1024) */ + pageshift -= 10; + + /* now determine which pageshift function is appropriate for the + result (have to because x << y is undefined for y < 0) */ + if( pageshift > 0 ) { + /* this is the most likely */ + p_pagetok = pagetok_left; + } else if( pageshift == 0 ) { + p_pagetok = pagetok_none; + } else { + p_pagetok = pagetok_right; + pageshift = -pageshift; + } + +#ifdef HAVE_KSTAT + registerMonitor( "mem/physical/free", "integer", + printMemFree, printMemFreeInfo, sm ); + registerMonitor( "mem/physical/used", "integer", + printMemUsed, printMemUsedInfo, sm ); +#endif + registerMonitor( "mem/swap/free", "integer", + printSwapFree, printSwapFreeInfo, sm ); + registerMonitor( "mem/swap/used", "integer", + printSwapUsed, printSwapUsedInfo, sm ); +} + +void exitMemory( void ) { +} + +int updateMemory( void ) { + + long swaptotal; + long swapfree; + long swapused; +#ifdef HAVE_KSTAT + kstat_ctl_t *kctl; + kstat_t *ksp; + kstat_named_t *kdata; +#endif /* HAVE_KSTAT */ + swaptotal = swapused = swapfree = 0L; + + /* + * Retrieve overall swap information from anonymous memory structure - + * which is the same way "swap -s" retrieves it's statistics. + * + * swapctl(SC_LIST, void *arg) does not return what we are looking for. + */ + + if (swapctl(SC_AINFO, &am_swap) == -1) + return(0); + + swaptotal = am_swap.ani_max; + swapused = am_swap.ani_resv; + swapfree = swaptotal - swapused; + + totalswap = pagetok(swaptotal); + freeswap = pagetok(swapfree); + +#ifdef HAVE_KSTAT + /* + * get a kstat handle and update the user's kstat chain + */ + if( (kctl = kstat_open()) == NULL ) + return( 0 ); + while( kstat_chain_update( kctl ) != 0 ) + ; + + totalmem = pagetok( sysconf( _SC_PHYS_PAGES )); + + /* + * traverse the kstat chain to find the appropriate statistics + */ + if( (ksp = kstat_lookup( kctl, "unix", 0, "system_pages" )) == NULL ) + return( 0 ); + if( kstat_read( kctl, ksp, NULL ) == -1 ) + return( 0 ); + + /* + * lookup the data + */ + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "freemem" ); + if( kdata != NULL ) + freemem = pagetok( kdata->value.ui32 ); + + kstat_close( kctl ); +#endif /* ! HAVE_KSTAT */ + + Dirty = 0; + + return( 0 ); +} + +void printMemFreeInfo( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "Free Memory\t0\t%ld\tKB\n", totalmem ); +} + +void printMemFree( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "%ld\n", freemem ); +} + +void printMemUsedInfo( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "Used Memory\t0\t%ld\tKB\n", totalmem ); +} + +void printMemUsed( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "%ld\n", totalmem - freemem ); +} + +void printSwapFreeInfo( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "Free Swap\t0\t%ld\tKB\n", totalswap ); +} + +void printSwapFree( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "%ld\n", freeswap ); +} + +void printSwapUsedInfo( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "Used Swap\t0\t%ld\tKB\n", totalswap ); +} + +void printSwapUsed( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "%ld\n", totalswap - freeswap ); +} diff --git a/ksysguard/ksysguardd/Solaris/Memory.h b/ksysguard/ksysguardd/Solaris/Memory.h new file mode 100644 index 000000000..7df6eb033 --- /dev/null +++ b/ksysguard/ksysguardd/Solaris/Memory.h @@ -0,0 +1,46 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@kde.org> + + Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + + 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 _Memory_h_ +#define _Memory_h_ + +typedef unsigned long t_memsize; + +#define PAGETOK(a) ((( (t_memsize) sysconf( _SC_PAGESIZE )) / (t_memsize) 1024) * (t_memsize) (a)) + +void initMemory(struct SensorModul* sm); +void exitMemory(void); + +int updateMemory(void); + +void printMemFree( const char *cmd ); +void printMemFreeInfo( const char *cmd ); +void printMemUsed( const char *cmd ); +void printMemUsedInfo( const char *cmd ); + +void printSwapFree( const char *cmd ); +void printSwapFreeInfo( const char *cmd ); +void printSwapUsed( const char *cmd ); +void printSwapUsedInfo( const char *cmd ); + +#endif /* _Memory_h */ diff --git a/ksysguard/ksysguardd/Solaris/NetDev.c b/ksysguard/ksysguardd/Solaris/NetDev.c new file mode 100644 index 000000000..89db266cb --- /dev/null +++ b/ksysguard/ksysguardd/Solaris/NetDev.c @@ -0,0 +1,679 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stropts.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <net/if.h> + +#include "config.h" + +#ifdef HAVE_KSTAT +#include <kstat.h> +#endif + +#include "ksysguardd.h" +#include "Command.h" +#include "NetDev.h" + +/* + * available network interface statistics through kstat(3): + * + * kstat name value + * ---------------------------------------------------------------------- + * for the loopback interface(s) we can get + * ipackets # packets received + * opackets # packets sent + * in addition to those, for "real" interfaces: + * oerrors # xmit errors + * ierrors # recv errors + * macxmt_errors # xmit errors reported by hardware? + * macrcv_errors # recv errors reported by hardware? + * opackets64 same as opackets (64bit) + * ipackets64 same as ipackets (64bit) + * obytes # bytes sent + * rbytes # bytes received + * obytes64 same as obytes (64bit) + * rbytes64 same as ibytes (64bit) + * collisions # collisions + * multixmt # multicasts sent? + * multircv # multicasts received? + * brdcstxmt # broadcasts transmitted + * brdcstrcv # broadcasts received + * unknowns + * blocked + * ex_collisions + * defer_xmts + * align_errors + * fcs_errors + * oflo # overflow errors + * uflo # underflow errors + * runt_errors + * missed + * tx_late_collisions + * carrier_errors + * noxmtbuf + * norcvbuf + * xmt_badinterp + * rcv_badinterp + * intr # interrupts? + * xmtretry # xmit retries? + * ifspeed interface speed: 10000000 for 10BaseT + * duplex "half" or "full" + * media e.g. "PHY/MII" + * promisc promiscuous mode (e.g. "off") + * first_collisions + * multi_collisions + * sqe_errors + * toolong_errors + */ + +typedef struct { + char *Name; + short flags; + unsigned long ipackets; + unsigned long OLDipackets; + unsigned long opackets; + unsigned long OLDopackets; + unsigned long ierrors; + unsigned long OLDierrors; + unsigned long oerrors; + unsigned long OLDoerrors; + unsigned long collisions; + unsigned long OLDcollisions; + unsigned long multixmt; + unsigned long OLDmultixmt; + unsigned long multircv; + unsigned long OLDmultircv; + unsigned long brdcstxmt; + unsigned long OLDbrdcstxmt; + unsigned long brdcstrcv; + unsigned long OLDbrdcstrcv; +} NetDevInfo; + + +#define NBUFFERS 64 +#define MAXNETDEVS 64 +static NetDevInfo IfInfo[MAXNETDEVS]; + +static int NetDevCount; + +/* + * insertnetdev() -- insert device name & flags into our list + */ +int insertnetdev( const char *name, const short flags ) { + + int i = 0; + + /* + * interface "aliases" don't seem to have + * separate kstat statistics, so we skip them + */ + if( strchr( name, (int) ':' ) != NULL ) + return( 0 ); + + while( (i < NetDevCount) && (strcmp( IfInfo[i].Name, name ) != 0) ) { + if( strcmp( IfInfo[i].Name, name ) == 0 ) + return( 0 ); + i++; + } + + /* + * init new slot + */ + IfInfo[i].Name = strdup( name ); + IfInfo[i].flags = flags; + IfInfo[i].ipackets = 0L; + IfInfo[i].OLDipackets = 0L; + IfInfo[i].opackets = 0L; + IfInfo[i].OLDopackets = 0L; + IfInfo[i].ierrors = 0L; + IfInfo[i].OLDierrors = 0L; + IfInfo[i].oerrors = 0L; + IfInfo[i].OLDoerrors = 0L; + IfInfo[i].collisions = 0L; + IfInfo[i].OLDcollisions = 0L; + IfInfo[i].multixmt = 0L; + IfInfo[i].OLDmultixmt = 0L; + IfInfo[i].multircv = 0L; + IfInfo[i].OLDmultircv = 0L; + IfInfo[i].brdcstxmt = 0L; + IfInfo[i].OLDbrdcstxmt = 0L; + IfInfo[i].brdcstrcv = 0L; + IfInfo[i].OLDbrdcstrcv = 0L; + NetDevCount = ++i; + + /* XXX: need sanity checks! */ + return( 0 ); +} + +/* + * getnetdevlist() -- get a list of all "up" interfaces + */ +int getnetdevlist( void ) { + + int fd; + int buffsize; + int prevsize; + int prevCount; + struct ifconf ifc; + struct ifreq *ifr; + + if( (fd = socket( PF_INET, SOCK_DGRAM, 0 )) < 0 ) { + return( -1 ); + } + + /* + * get the interface list via iotl( SIOCGIFCONF ) + * the following algorithm based on ideas from W.R. Stevens' + * "UNIX Network Programming", Vol. 1: + * Since the ioctl may return 0, indicating success, even if the + * ifreq buffer was too small, we have to make sure, it didn't + * get truncated by comparing our initial size guess with the + * actual returned size. + */ + prevsize = 0; + buffsize = NBUFFERS * sizeof( struct ifreq ); + while( 1 ) { + if( (ifc.ifc_buf = malloc( buffsize )) == NULL ) + return( -1 ); + + ifc.ifc_len = buffsize; + if( ioctl( fd, SIOCGIFCONF, &ifc ) < 0 ) { + if( errno != EINVAL || prevsize != 0 ) { + free( ifc.ifc_buf ); + return( -1 ); + } + } else { + if( ifc.ifc_len == prevsize ) + /* success */ + break; + prevsize = ifc.ifc_len; + } + /* + * initial buffer guessed too small, allocate a bigger one + */ + free( ifc.ifc_buf ); + buffsize = (NBUFFERS + 10) * sizeof( struct ifreq ); + } + + /* + * get the names for all interfaces which are configured "up" + * we're not interested in the ifc data (address), so we reuse the + * same structure (with ifc.len set) for the next ioctl() + */ + prevCount = NetDevCount; + for( ifr = (struct ifreq *) ifc.ifc_buf; + ifr < (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); + ifr++ ) { + if( ioctl( fd, SIOCGIFFLAGS, ifr ) < 0 ) { + free( ifc.ifc_buf ); + return( -1 ); + } + if( ifr->ifr_flags & IFF_UP ) + insertnetdev( ifr->ifr_name, ifr->ifr_flags ); + } + free( ifc.ifc_buf ); + close( fd ); + + if( (prevCount > 0) && (prevCount != NetDevCount) ) { + print_error( "RECONFIGURE\n" ); + prevCount = NetDevCount; + } + + return( NetDevCount ); +} + +void initNetDev( struct SensorModul* sm ) { +#ifdef HAVE_KSTAT + char mon[128]; + int i; + + getnetdevlist(); + for( i = 0; i < NetDevCount; i++ ) { + sprintf( mon, "network/%s/ipackets", IfInfo[i].Name ); + registerMonitor( mon, "integer", + printIPackets, printIPacketsInfo, sm ); + sprintf( mon, "network/%s/opackets", IfInfo[i].Name ); + registerMonitor( mon, "integer", + printOPackets, printOPacketsInfo, sm ); + /* + * if this isn't a loopback interface, + * register additional monitors + */ + if( ! (IfInfo[i].flags & IFF_LOOPBACK) ) { + /* + * recv errors + */ + sprintf( mon, "network/%s/ierrors", + IfInfo[i].Name ); + registerMonitor( mon, "integer", + printIErrors, printIErrorsInfo, sm ); + /* + * xmit errors + */ + sprintf( mon, "network/%s/oerrors", + IfInfo[i].Name ); + registerMonitor( mon, "integer", + printOErrors, printOErrorsInfo, sm ); + /* + * collisions + */ + sprintf( mon, "network/%s/collisions", + IfInfo[i].Name ); + registerMonitor( mon, "integer", + printCollisions, printCollisionsInfo, sm ); + /* + * multicast xmits + */ + sprintf( mon, "network/%s/multixmt", + IfInfo[i].Name ); + registerMonitor( mon, "integer", + printMultiXmits, printMultiXmitsInfo, sm ); + /* + * multicast recvs + */ + sprintf( mon, "network/%s/multircv", + IfInfo[i].Name ); + registerMonitor( mon, "integer", + printMultiRecvs, printMultiRecvsInfo, sm ); + /* + * broadcast xmits + */ + sprintf( mon, "network/%s/brdcstxmt", + IfInfo[i].Name ); + registerMonitor( mon, "integer", + printBcastXmits, printBcastXmitsInfo, sm ); + /* + * broadcast recvs + */ + sprintf( mon, "network/%s/brdcstrcv", + IfInfo[i].Name ); + registerMonitor( mon, "integer", + printBcastRecvs, printBcastRecvsInfo, sm ); + } + } +#endif +} + +void exitNetDev( void ) { +} + +int updateNetDev( void ) { + +#ifdef HAVE_KSTAT + kstat_ctl_t *kctl; + kstat_t *ksp; + kstat_named_t *kdata; + int i; + + /* + * get a kstat handle and update the user's kstat chain + */ + if( (kctl = kstat_open()) == NULL ) + return( 0 ); + while( kstat_chain_update( kctl ) != 0 ) + ; + + for( i = 0; i < NetDevCount; i++ ) { + char *name; + char *ptr; + + /* + * chop off the trailing interface no + */ + name = strdup( IfInfo[i].Name ); + ptr = name + strlen( name ) - 1; + while( (ptr > name) && isdigit( (int) *ptr ) ) { + *ptr = '\0'; + ptr--; + } + + /* + * traverse the kstat chain + * to find the appropriate statistics + */ + if( (ksp = kstat_lookup( kctl, + name, 0, IfInfo[i].Name )) == NULL ) { + free( name ); + return( 0 ); + } + if( kstat_read( kctl, ksp, NULL ) == -1 ) { + free( name ); + return( 0 ); + } + free( name ); + + /* + * lookup & store the data + */ + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "ipackets" ); + if( kdata != NULL ) { + IfInfo[i].OLDipackets = IfInfo[i].ipackets; + IfInfo[i].ipackets = kdata->value.ul; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "opackets" ); + if( kdata != NULL ) { + IfInfo[i].OLDopackets = IfInfo[i].opackets; + IfInfo[i].opackets = kdata->value.ul; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "ierrors" ); + if( kdata != NULL ) { + IfInfo[i].OLDierrors = IfInfo[i].ierrors; + IfInfo[i].ierrors = kdata->value.ul; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "oerrors" ); + if( kdata != NULL ) { + IfInfo[i].OLDoerrors = IfInfo[i].oerrors; + IfInfo[i].oerrors = kdata->value.ul; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "collisions" ); + if( kdata != NULL ) { + IfInfo[i].OLDcollisions = IfInfo[i].collisions; + IfInfo[i].collisions = kdata->value.ul; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "multixmt" ); + if( kdata != NULL ) { + IfInfo[i].OLDmultixmt = IfInfo[i].multixmt; + IfInfo[i].multixmt = kdata->value.ul; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "multircv" ); + if( kdata != NULL ) { + IfInfo[i].OLDmultircv = IfInfo[i].multircv; + IfInfo[i].multircv = kdata->value.ul; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "brdcstxmt" ); + if( kdata != NULL ) { + IfInfo[i].OLDbrdcstxmt = IfInfo[i].brdcstxmt; + IfInfo[i].brdcstxmt = kdata->value.ul; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "brdcstrcv" ); + if( kdata != NULL ) { + IfInfo[i].OLDbrdcstrcv = IfInfo[i].brdcstrcv; + IfInfo[i].brdcstrcv = kdata->value.ul; + } + } + + kstat_close( kctl ); +#endif /* ! HAVE_KSTAT */ + + return( 0 ); +} + +void printIPacketsInfo( const char *cmd ) { + fprintf(CurrentClient, "Received Packets\t0\t0\tPackets\n" ); +} + +void printIPackets( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDipackets > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].ipackets - IfInfo[i].OLDipackets); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} + +void printOPacketsInfo( const char *cmd ) { + fprintf(CurrentClient, "Transmitted Packets\t0\t0\tPackets\n" ); +} + +void printOPackets( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDopackets > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].opackets - IfInfo[i].OLDopackets ); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} + +void printIErrorsInfo( const char *cmd ) { + fprintf(CurrentClient, "Input Errors\t0\t0\tPackets\n" ); +} + +void printIErrors( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDierrors > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].ierrors - IfInfo[i].OLDierrors ); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} + +void printOErrorsInfo( const char *cmd ) { + fprintf(CurrentClient, "Output Errors\t0\t0\tPackets\n" ); +} + +void printOErrors( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDoerrors > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].oerrors - IfInfo[i].OLDoerrors ); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} + +void printCollisionsInfo( const char *cmd ) { + fprintf(CurrentClient, "Collisions\t0\t0\tPackets\n" ); +} + +void printCollisions( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDcollisions > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].collisions - IfInfo[i].OLDcollisions ); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} + +void printMultiXmitsInfo( const char *cmd ) { + fprintf(CurrentClient, "Multicasts Sent\t0\t0\tPackets\n" ); +} + +void printMultiXmits( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDmultixmt > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].multixmt - IfInfo[i].OLDmultixmt ); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} + +void printMultiRecvsInfo( const char *cmd ) { + fprintf(CurrentClient, "Multicasts Received\t0\t0\tPackets\n" ); +} + +void printMultiRecvs( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDmultircv > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].multircv - IfInfo[i].OLDmultircv ); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} + +void printBcastXmitsInfo( const char *cmd ) { + fprintf(CurrentClient, "Broadcasts Sent\t0\t0\tPackets\n" ); +} + +void printBcastXmits( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDbrdcstxmt > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].brdcstxmt - IfInfo[i].OLDbrdcstxmt ); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} + +void printBcastRecvsInfo( const char *cmd ) { + fprintf(CurrentClient, "Broadcasts Received\t0\t0\tPackets\n" ); +} + +void printBcastRecvs( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDbrdcstrcv > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].brdcstrcv - IfInfo[i].OLDbrdcstrcv ); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} diff --git a/ksysguard/ksysguardd/Solaris/NetDev.h b/ksysguard/ksysguardd/Solaris/NetDev.h new file mode 100644 index 000000000..b6ff54448 --- /dev/null +++ b/ksysguard/ksysguardd/Solaris/NetDev.h @@ -0,0 +1,59 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@kde.org> + + Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + + 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 _NetDev_h_ +#define _NetDev_h_ + +void initNetDev(struct SensorModul* sm); +void exitNetDev(void); + +int updateNetDev(void); + +void printIPacketsInfo( const char *cmd ); +void printIPackets( const char *cmd ); + +void printOPacketsInfo( const char *cmd ); +void printOPackets( const char *cmd ); + +void printIErrorsInfo( const char *cmd ); +void printIErrors( const char *cmd ); + +void printOErrorsInfo( const char *cmd ); +void printOErrors( const char *cmd ); + +void printCollisionsInfo( const char *cmd ); +void printCollisions( const char *cmd ); + +void printMultiXmitsInfo( const char *cmd ); +void printMultiXmits( const char *cmd ); + +void printMultiRecvsInfo( const char *cmd ); +void printMultiRecvs( const char *cmd ); + +void printBcastXmitsInfo( const char *cmd ); +void printBcastXmits( const char *cmd ); + +void printBcastRecvsInfo( const char *cmd ); +void printBcastRecvs( const char *cmd ); + +#endif /* _NetDev_h */ diff --git a/ksysguard/ksysguardd/Solaris/ProcessList.c b/ksysguard/ksysguardd/Solaris/ProcessList.c new file mode 100644 index 000000000..771371b76 --- /dev/null +++ b/ksysguard/ksysguardd/Solaris/ProcessList.c @@ -0,0 +1,436 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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. + +*/ + +/* Stop <sys/procfs.h> from crapping out on 32-bit architectures. */ + +#if !defined(_LP64) && _FILE_OFFSET_BITS == 64 +# undef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 32 +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/types.h> +#include <dirent.h> +#include <pwd.h> +#include <procfs.h> +#include <sys/proc.h> +#include <sys/resource.h> + +#include "ccont.h" +#include "../../gui/SignalIDs.h" +#include "ksysguardd.h" + +#include "Command.h" +#include "ProcessList.h" + +#define BUFSIZE 1024 + +typedef struct { + int alive; /* for "garbage collection" */ + pid_t pid; /* process ID */ + pid_t ppid; /* parent process ID */ + uid_t uid; /* process owner (real UID) */ + gid_t gid; /* process group (real GID) */ + char *userName; /* process owner (name) */ + int nThreads; /* # of threads in this process */ + int Prio; /* scheduling priority */ + size_t Size; /* total size of process image */ + size_t RSSize; /* resident set size */ + char *State; /* process state */ + int Time; /* CPU time for the process */ + double Load; /* CPU load in % */ + char *Command; /* command name */ + char *CmdLine; /* command line */ +} ProcessInfo; + +static CONTAINER ProcessList = 0; +static unsigned ProcessCount = 0; /* # of processes */ +static DIR *procdir; /* handle for /proc */ + +/* + * lwpStateName() -- return string representation of process state + */ +char *lwpStateName( lwpsinfo_t lwpinfo ) { + + char result[8]; + int processor; + + switch( (int) lwpinfo.pr_state ) { + case SSLEEP: + sprintf( result, "%s", "sleep" ); + break; + case SRUN: + sprintf( result, "%s", "run" ); + break; + case SZOMB: + sprintf( result, "%s", "zombie" ); + break; + case SSTOP: + sprintf( result, "%s", "stop" ); + break; + case SIDL: + sprintf( result, "%s", "start" ); + break; + case SONPROC: + processor = (int) lwpinfo.pr_onpro; + sprintf( result, "%s/%d", "cpu", processor ); + break; + default: + sprintf( result, "%s", "???" ); + break; + } + + return( strdup( result )); +} + +static void validateStr( char *string ) { + + char *ptr = string; + + /* + * remove all chars that might screw up communication + */ + while( *ptr != '\0' ) { + if( *ptr == '\t' || *ptr == '\n' || *ptr == '\r' ) + *ptr = ' '; + ptr++; + } + /* + * make sure there's at least one char + */ + if( string[0] == '\0' ) + strcpy( string, " " ); +} + +static int processCmp( void *p1, void *p2 ) { + + return( ((ProcessInfo *) p1)->pid - ((ProcessInfo *) p2)->pid ); +} + +static ProcessInfo *findProcessInList( pid_t pid ) { + + ProcessInfo key; + long index; + + key.pid = pid; + if( (index = search_ctnr( ProcessList, processCmp, &key )) < 0 ) + return( NULL ); + + return( get_ctnr( ProcessList, index )); +} + +static int updateProcess( pid_t pid ) { + + ProcessInfo *ps; + int fd; + char buf[BUFSIZE]; + psinfo_t psinfo; + struct passwd *pw; + + if( (ps = findProcessInList( pid )) == NULL ) { + if( (ps = (ProcessInfo *) malloc( sizeof( ProcessInfo ))) + == NULL ) { + print_error( "cannot malloc()\n" ); + return( -1 ); + } + ps->pid = pid; + ps->userName = NULL; + ps->State = NULL; + ps->Command = NULL; + ps->CmdLine = NULL; + ps->alive = 0; + + push_ctnr( ProcessList, ps ); + bsort_ctnr( ProcessList, processCmp ); + } + + snprintf( buf, BUFSIZE - 1, "%s/%ld/psinfo", PROCDIR, pid ); + if( (fd = open( buf, O_RDONLY )) < 0 ) { + return( -1 ); + } + + if( read( fd, &psinfo, sizeof( psinfo_t )) != sizeof( psinfo_t )) { + close( fd ); + return( -1 ); + } + close( fd ); + + ps->ppid = psinfo.pr_ppid; + ps->uid = psinfo.pr_uid; + ps->gid = psinfo.pr_gid; + + pw = getpwuid( psinfo.pr_uid ); + if( ps->userName != NULL ) + free( ps->userName ); + ps->userName = strdup( pw->pw_name ); + + if( ps->State != NULL ) + free( ps->State ); + ps->State = lwpStateName( psinfo.pr_lwp ); + + /* + * the following data is invalid for zombies, so... + */ + if( (ps->nThreads = psinfo.pr_nlwp ) != 0 ) { + ps->Prio = psinfo.pr_lwp.pr_pri; + ps->Time = psinfo.pr_lwp.pr_time.tv_sec * 100 + + psinfo.pr_lwp.pr_time.tv_nsec * 10000000; + ps->Load = (double) psinfo.pr_lwp.pr_pctcpu + / (double) 0x8000 * 100.0; + } else { + ps->Prio = 0; + ps->Time = 0; + ps->Load = 0.0; + } + + ps->Size = psinfo.pr_size; + ps->RSSize = psinfo.pr_rssize; + + if( ps->Command != NULL ) + free( ps->Command ); + ps->Command = strdup( psinfo.pr_fname ); + if( ps->CmdLine != NULL ) + free( ps->CmdLine ); + ps->CmdLine = strdup( psinfo.pr_psargs ); + + validateStr( ps->Command ); + validateStr( ps->CmdLine ); + + ps->alive = 1; + + return( 0 ); +} + +static void cleanupProcessList( void ) { + + ProcessInfo *ps; + + ProcessCount = 0; + for( ps = first_ctnr( ProcessList ); ps; ps = next_ctnr( ProcessList )) { + if( ps->alive ) { + ps->alive = 0; + ProcessCount++; + } else { + free( remove_ctnr( ProcessList )); + } + } +} + +void initProcessList( struct SensorModul* sm ) { + + if( (procdir = opendir( PROCDIR )) == NULL ) { + print_error( "cannot open \"%s\" for reading\n", PROCDIR ); + return; + } + + ProcessList = new_ctnr(); + + /* + * register the supported monitors & commands + */ + registerMonitor( "pscount", "integer", + printProcessCount, printProcessCountInfo, sm ); + registerMonitor( "ps", "table", + printProcessList, printProcessListInfo, sm ); + + registerCommand( "kill", killProcess ); + registerCommand( "setpriority", setPriority ); +} + +void exitProcessList( void ) { + + destr_ctnr( ProcessList, free ); +} + +int updateProcessList( void ) { + + struct dirent *de; + + rewinddir( procdir ); + while( (de = readdir( procdir )) != NULL ) { + /* + * skip '.' and '..' + */ + if( de->d_name[0] == '.' ) + continue; + + /* + * fetch the process info and insert it into the info table + */ + updateProcess( (pid_t) atol( de->d_name )); + } + cleanupProcessList(); + + return( 0 ); +} + +void printProcessListInfo( const char *cmd ) { + fprintf(CurrentClient, "Name\tPID\tPPID\tGID\tStatus\tUser\tThreads" + "\tSize\tResident\t%% CPU\tPriority\tCommand\n" ); + fprintf(CurrentClient, "s\td\td\td\ts\ts\td\tD\tD\tf\td\ts\n" ); +} + +void printProcessList( const char *cmd ) { + + ProcessInfo *ps; + + for( ps = first_ctnr( ProcessList ); ps; ps = next_ctnr( ProcessList )) { + fprintf(CurrentClient, + "%s\t%ld\t%ld\t%ld\t%s\t%s\t%d\t%d\t%d\t%.2f\t%d\t%s\n", + ps->Command, + (long) ps->pid, + (long) ps->ppid, + (long) ps->gid, + ps->State, + ps->userName, + ps->nThreads, + ps->Size, + ps->RSSize, + ps->Load, + ps->Prio, + ps->CmdLine); + } + + fprintf(CurrentClient, "\n"); +} + +void printProcessCount( const char *cmd ) { + fprintf(CurrentClient, "%d\n", ProcessCount ); +} + +void printProcessCountInfo( const char *cmd ) { + fprintf(CurrentClient, "Number of Processes\t0\t0\t\n" ); +} + +void killProcess( const char *cmd ) { + + int sig, pid; + + sscanf( cmd, "%*s %d %d", &pid, &sig ); + + switch( sig ) { + case MENU_ID_SIGABRT: + sig = SIGABRT; + break; + case MENU_ID_SIGALRM: + sig = SIGALRM; + break; + case MENU_ID_SIGCHLD: + sig = SIGCHLD; + break; + case MENU_ID_SIGCONT: + sig = SIGCONT; + break; + case MENU_ID_SIGFPE: + sig = SIGFPE; + break; + case MENU_ID_SIGHUP: + sig = SIGHUP; + break; + case MENU_ID_SIGILL: + sig = SIGILL; + break; + case MENU_ID_SIGINT: + sig = SIGINT; + break; + case MENU_ID_SIGKILL: + sig = SIGKILL; + break; + case MENU_ID_SIGPIPE: + sig = SIGPIPE; + break; + case MENU_ID_SIGQUIT: + sig = SIGQUIT; + break; + case MENU_ID_SIGSEGV: + sig = SIGSEGV; + break; + case MENU_ID_SIGSTOP: + sig = SIGSTOP; + break; + case MENU_ID_SIGTERM: + sig = SIGTERM; + break; + case MENU_ID_SIGTSTP: + sig = SIGTSTP; + break; + case MENU_ID_SIGTTIN: + sig = SIGTTIN; + break; + case MENU_ID_SIGTTOU: + sig = SIGTTOU; + break; + case MENU_ID_SIGUSR1: + sig = SIGUSR1; + break; + case MENU_ID_SIGUSR2: + sig = SIGUSR2; + break; + } + if( kill( (pid_t) pid, sig )) { + switch( errno ) { + case EINVAL: + fprintf(CurrentClient, "4\n" ); + break; + case ESRCH: + fprintf(CurrentClient, "3\n" ); + break; + case EPERM: + fprintf(CurrentClient, "2\n" ); + break; + default: + fprintf(CurrentClient, "1\n" ); /* unknown error */ + break; + } + } else + fprintf(CurrentClient, "0\n"); +} + +void setPriority( const char *cmd ) { + int pid, prio; + + sscanf( cmd, "%*s %d %d", &pid, &prio ); + if( setpriority( PRIO_PROCESS, pid, prio )) { + switch( errno ) { + case EINVAL: + fprintf(CurrentClient, "4\n" ); + break; + case ESRCH: + fprintf(CurrentClient, "3\n" ); + break; + case EPERM: + case EACCES: + fprintf(CurrentClient, "2\n" ); + break; + default: + fprintf(CurrentClient, "1\n" ); /* unknown error */ + break; + } + } else + fprintf(CurrentClient, "0\n"); +} diff --git a/ksysguard/ksysguardd/Solaris/ProcessList.h b/ksysguard/ksysguardd/Solaris/ProcessList.h new file mode 100644 index 000000000..90333f5b8 --- /dev/null +++ b/ksysguard/ksysguardd/Solaris/ProcessList.h @@ -0,0 +1,43 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@kde.org> + + Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + + 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 _ProcessList_H_ +#define _ProcessList_H_ + +#define PROCDIR "/proc" + +void initProcessList(struct SensorModul* sm); +void exitProcessList(void); + +int updateProcessList(void); + +void printProcessList(const char*); +void printProcessListInfo(const char*); + +void printProcessCount(const char* cmd); +void printProcessCountInfo(const char* cmd); + +void killProcess(const char* cmd); +void setPriority(const char* cmd); + +#endif diff --git a/ksysguard/ksysguardd/Tru64/LoadAvg.c b/ksysguard/ksysguardd/Tru64/LoadAvg.c new file mode 100644 index 000000000..ddbe68e2d --- /dev/null +++ b/ksysguard/ksysguardd/Tru64/LoadAvg.c @@ -0,0 +1,121 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/swap.h> + +#include "config.h" + +#ifdef HAVE_KSTAT +#include <kstat.h> +#endif + +#include "ksysguardd.h" +#include "Command.h" +#include "LoadAvg.h" + +double loadavg1 = 0.0; +double loadavg5 = 0.0; +double loadavg15 = 0.0; + +void initLoadAvg( struct SensorModul* sm ) { +#ifdef HAVE_KSTAT + registerMonitor( "cpu/loadavg1", "float", + printLoadAvg1, printLoadAvg1Info, sm ); + registerMonitor( "cpu/loadavg5", "float", + printLoadAvg5, printLoadAvg5Info, sm ); + registerMonitor( "cpu/loadavg15", "float", + printLoadAvg15, printLoadAvg15Info, sm ); +#endif +} + +void exitLoadAvg( void ) { +} + +int updateLoadAvg( void ) { + +#ifdef HAVE_KSTAT + kstat_ctl_t *kctl; + kstat_t *ksp; + kstat_named_t *kdata; + + /* + * get a kstat handle and update the user's kstat chain + */ + if( (kctl = kstat_open()) == NULL ) + return( 0 ); + while( kstat_chain_update( kctl ) != 0 ) + ; + + /* + * traverse the kstat chain to find the appropriate statistics + */ + if( (ksp = kstat_lookup( kctl, "unix", 0, "system_misc" )) == NULL ) + return( 0 ); + if( kstat_read( kctl, ksp, NULL ) == -1 ) + return( 0 ); + + /* + * lookup the data + */ + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "avenrun_1min" ); + if( kdata != NULL ) + loadavg1 = LOAD( kdata->value.ui32 ); + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "avenrun_5min" ); + if( kdata != NULL ) + loadavg5 = LOAD( kdata->value.ui32 ); + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "avenrun_15min" ); + if( kdata != NULL ) + loadavg15 = LOAD( kdata->value.ui32 ); + + kstat_close( kctl ); +#endif /* ! HAVE_KSTAT */ + + return( 0 ); +} + +void printLoadAvg1Info( const char *cmd ) { + fprintf(CurrentClient, "avnrun 1min\t0\t0\n" ); +} + +void printLoadAvg1( const char *cmd ) { + fprintf(CurrentClient, "%f\n", loadavg1 ); +} + +void printLoadAvg5Info( const char *cmd ) { + fprintf(CurrentClient, "avnrun 5min\t0\t0\n" ); +} + +void printLoadAvg5( const char *cmd ) { + fprintf(CurrentClient, "%f\n", loadavg5 ); +} + +void printLoadAvg15Info( const char *cmd ) { + fprintf(CurrentClient, "avnrun 15min\t0\t0\n" ); +} + +void printLoadAvg15( const char *cmd ) { + fprintf(CurrentClient, "%f\n", loadavg15 ); +} diff --git a/ksysguard/ksysguardd/Tru64/LoadAvg.h b/ksysguard/ksysguardd/Tru64/LoadAvg.h new file mode 100644 index 000000000..eea8ad82e --- /dev/null +++ b/ksysguard/ksysguardd/Tru64/LoadAvg.h @@ -0,0 +1,41 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@kde.org> + + Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + + 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 _LoadAvg_h_ +#define _LoadAvg_h_ + +#define LOAD(a) ((double)(a) / (1 << 8 )) + +void initLoadAvg(struct SensorModul* sm); +void exitLoadAvg(void); + +int updateLoadAvg(void); + +void printLoadAvg1( const char *cmd ); +void printLoadAvg1Info( const char *cmd ); +void printLoadAvg5( const char *cmd ); +void printLoadAvg5Info( const char *cmd ); +void printLoadAvg15( const char *cmd ); +void printLoadAvg15Info( const char *cmd ); + +#endif /* _LoadAvg_h_ */ diff --git a/ksysguard/ksysguardd/Tru64/Makefile.am b/ksysguard/ksysguardd/Tru64/Makefile.am new file mode 100644 index 000000000..95be0247b --- /dev/null +++ b/ksysguard/ksysguardd/Tru64/Makefile.am @@ -0,0 +1,8 @@ +# +# +AM_CFLAGS = -Wall + +INCLUDES = -I$(srcdir)/../../CContLib -I.. + +lib_LIBRARIES = libksysguardd.a +libksysguardd_a_SOURCES = Memory.c LoadAvg.c NetDev.c diff --git a/ksysguard/ksysguardd/Tru64/Memory.c b/ksysguard/ksysguardd/Tru64/Memory.c new file mode 100644 index 000000000..3a9332064 --- /dev/null +++ b/ksysguard/ksysguardd/Tru64/Memory.c @@ -0,0 +1,237 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/swap.h> + +#include "config.h" + +#ifdef HAVE_KSTAT +#include <kstat.h> +#endif + +#include "ksysguardd.h" +#include "Command.h" +#include "Memory.h" + +static int Dirty = 1; +static t_memsize totalmem = (t_memsize) 0; +static t_memsize freemem = (t_memsize) 0; +static long totalswap = 0L; +static long freeswap = 0L; + +/* + * this is borrowed from top's m_sunos5 module + * used by permission from William LeFebvre + */ +static int pageshift; +static long (*p_pagetok) (); +#define pagetok(size) ((*p_pagetok)(size)) + +long pagetok_none( long size ) { + return( size ); +} + +long pagetok_left( long size ) { + return( size << pageshift ); +} + +long pagetok_right( long size ) { + return( size >> pageshift ); +} + +void initMemory( struct SensorModul* sm ) { + + long i = sysconf( _SC_PAGESIZE ); + + pageshift = 0; + while( (i >>= 1) > 0 ) + pageshift++; + + /* calculate an amount to shift to K values */ + /* remember that log base 2 of 1024 is 10 (i.e.: 2^10 = 1024) */ + pageshift -= 10; + + /* now determine which pageshift function is appropriate for the + result (have to because x << y is undefined for y < 0) */ + if( pageshift > 0 ) { + /* this is the most likely */ + p_pagetok = pagetok_left; + } else if( pageshift == 0 ) { + p_pagetok = pagetok_none; + } else { + p_pagetok = pagetok_right; + pageshift = -pageshift; + } + +#ifdef HAVE_KSTAT + registerMonitor( "mem/physical/free", "integer", + printMemFree, printMemFreeInfo, sm ); + registerMonitor( "mem/physical/used", "integer", + printMemUsed, printMemUsedInfo, sm ); +#endif + registerMonitor( "mem/swap/free", "integer", + printSwapFree, printSwapFreeInfo, sm ); + registerMonitor( "mem/swap/used", "integer", + printSwapUsed, printSwapUsedInfo, sm ); +} + +void exitMemory( void ) { +} + +int updateMemory( void ) { + + struct swaptable *swt; + struct swapent *ste; + int i; + int ndevs; + long swaptotal; + long swapfree; + char dummy[128]; +#ifdef HAVE_KSTAT + kstat_ctl_t *kctl; + kstat_t *ksp; + kstat_named_t *kdata; +#endif /* HAVE_KSTAT */ + + if( (ndevs = swapctl( SC_GETNSWP, NULL )) < 1 ) + return( 0 ); + if( (swt = (struct swaptable *) malloc( + sizeof( int ) + + ndevs * sizeof( struct swapent ))) == NULL ) + return( 0 ); + + /* + * fill in the required fields and retrieve the info thru swapctl() + */ + swt->swt_n = ndevs; + ste = &(swt->swt_ent[0]); + for( i = 0; i < ndevs; i++ ) { + /* + * since we'renot interested in the path(s), + * we'll re-use the same buffer + */ + ste->ste_path = dummy; + ste++; + } + swapctl( SC_LIST, swt ); + + swaptotal = swapfree = 0L; + + ste = &(swt->swt_ent[0]); + for( i = 0; i < ndevs; i++ ) { + if( (! (ste->ste_flags & ST_INDEL)) + && (! (ste->ste_flags & ST_DOINGDEL)) ) { + swaptotal += ste->ste_pages; + swapfree += ste->ste_free; + } + ste++; + } + free( swt ); + + totalswap = pagetok( swaptotal ); + freeswap = pagetok( swapfree ); + +#ifdef HAVE_KSTAT + /* + * get a kstat handle and update the user's kstat chain + */ + if( (kctl = kstat_open()) == NULL ) + return( 0 ); + while( kstat_chain_update( kctl ) != 0 ) + ; + + totalmem = pagetok( sysconf( _SC_PHYS_PAGES )); + + /* + * traverse the kstat chain to find the appropriate statistics + */ + if( (ksp = kstat_lookup( kctl, "unix", 0, "system_pages" )) == NULL ) + return( 0 ); + if( kstat_read( kctl, ksp, NULL ) == -1 ) + return( 0 ); + + /* + * lookup the data + */ + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "freemem" ); + if( kdata != NULL ) + freemem = pagetok( kdata->value.ui32 ); + + kstat_close( kctl ); +#endif /* ! HAVE_KSTAT */ + + Dirty = 0; + + return( 0 ); +} + +void printMemFreeInfo( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "Free Memory\t0\t%ld\tKB\n", totalmem ); +} + +void printMemFree( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "%ld\n", freemem ); +} + +void printMemUsedInfo( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "Used Memory\t0\t%ld\tKB\n", totalmem ); +} + +void printMemUsed( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "%ld\n", totalmem - freemem ); +} + +void printSwapFreeInfo( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "Free Swap\t0\t%ld\tKB\n", totalswap ); +} + +void printSwapFree( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "%ld\n", freeswap ); +} + +void printSwapUsedInfo( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "Used Swap\t0\t%ld\tKB\n", totalswap ); +} + +void printSwapUsed( const char *cmd ) { + if( Dirty ) + updateMemory(); + fprintf(CurrentClient, "%ld\n", totalswap - freeswap ); +} diff --git a/ksysguard/ksysguardd/Tru64/Memory.h b/ksysguard/ksysguardd/Tru64/Memory.h new file mode 100644 index 000000000..7df6eb033 --- /dev/null +++ b/ksysguard/ksysguardd/Tru64/Memory.h @@ -0,0 +1,46 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@kde.org> + + Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + + 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 _Memory_h_ +#define _Memory_h_ + +typedef unsigned long t_memsize; + +#define PAGETOK(a) ((( (t_memsize) sysconf( _SC_PAGESIZE )) / (t_memsize) 1024) * (t_memsize) (a)) + +void initMemory(struct SensorModul* sm); +void exitMemory(void); + +int updateMemory(void); + +void printMemFree( const char *cmd ); +void printMemFreeInfo( const char *cmd ); +void printMemUsed( const char *cmd ); +void printMemUsedInfo( const char *cmd ); + +void printSwapFree( const char *cmd ); +void printSwapFreeInfo( const char *cmd ); +void printSwapUsed( const char *cmd ); +void printSwapUsedInfo( const char *cmd ); + +#endif /* _Memory_h */ diff --git a/ksysguard/ksysguardd/Tru64/NetDev.c b/ksysguard/ksysguardd/Tru64/NetDev.c new file mode 100644 index 000000000..0699b929a --- /dev/null +++ b/ksysguard/ksysguardd/Tru64/NetDev.c @@ -0,0 +1,678 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org> + + Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stropts.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> + +#include "config.h" + +#ifdef HAVE_KSTAT +#include <kstat.h> +#endif + +#include "ksysguardd.h" +#include "Command.h" +#include "NetDev.h" + +/* + * available network interface statistics through kstat(3): + * + * kstat name value + * ---------------------------------------------------------------------- + * for the loopback interface(s) we can get + * ipackets # packets received + * opackets # packets sent + * in addition to those, for "real" interfaces: + * oerrors # xmit errors + * ierrors # recv errors + * macxmt_errors # xmit errors reported by hardware? + * macrcv_errors # recv errors reported by hardware? + * opackets64 same as opackets (64bit) + * ipackets64 same as ipackets (64bit) + * obytes # bytes sent + * rbytes # bytes received + * obytes64 same as obytes (64bit) + * rbytes64 same as ibytes (64bit) + * collisions # collisions + * multixmt # multicasts sent? + * multircv # multicasts received? + * brdcstxmt # broadcasts transmitted + * brdcstrcv # broadcasts received + * unknowns + * blocked + * ex_collisions + * defer_xmts + * align_errors + * fcs_errors + * oflo # overflow errors + * uflo # underflow errors + * runt_errors + * missed + * tx_late_collisions + * carrier_errors + * noxmtbuf + * norcvbuf + * xmt_badinterp + * rcv_badinterp + * intr # interrupts? + * xmtretry # xmit retries? + * ifspeed interface speed: 10000000 for 10BaseT + * duplex "half" or "full" + * media e.g. "PHY/MII" + * promisc promiscuous mode (e.g. "off") + * first_collisions + * multi_collisions + * sqe_errors + * toolong_errors + */ + +typedef struct { + char *Name; + short flags; + unsigned long ipackets; + unsigned long OLDipackets; + unsigned long opackets; + unsigned long OLDopackets; + unsigned long ierrors; + unsigned long OLDierrors; + unsigned long oerrors; + unsigned long OLDoerrors; + unsigned long collisions; + unsigned long OLDcollisions; + unsigned long multixmt; + unsigned long OLDmultixmt; + unsigned long multircv; + unsigned long OLDmultircv; + unsigned long brdcstxmt; + unsigned long OLDbrdcstxmt; + unsigned long brdcstrcv; + unsigned long OLDbrdcstrcv; +} NetDevInfo; + + +#define NBUFFERS 64 +#define MAXNETDEVS 64 +static NetDevInfo IfInfo[MAXNETDEVS]; + +static int NetDevCount; + +/* + * insertnetdev() -- insert device name & flags into our list + */ +int insertnetdev( const char *name, const short flags ) { + + int i = 0; + + /* + * interface "aliases" don't seem to have + * separate kstat statistics, so we skip them + */ + if( strchr( name, (int) ':' ) != NULL ) + return( 0 ); + + while( (i < NetDevCount) && (strcmp( IfInfo[i].Name, name ) != 0) ) { + if( strcmp( IfInfo[i].Name, name ) == 0 ) + return( 0 ); + i++; + } + + /* + * init new slot + */ + IfInfo[i].Name = strdup( name ); + IfInfo[i].flags = flags; + IfInfo[i].ipackets = 0L; + IfInfo[i].OLDipackets = 0L; + IfInfo[i].opackets = 0L; + IfInfo[i].OLDopackets = 0L; + IfInfo[i].ierrors = 0L; + IfInfo[i].OLDierrors = 0L; + IfInfo[i].oerrors = 0L; + IfInfo[i].OLDoerrors = 0L; + IfInfo[i].collisions = 0L; + IfInfo[i].OLDcollisions = 0L; + IfInfo[i].multixmt = 0L; + IfInfo[i].OLDmultixmt = 0L; + IfInfo[i].multircv = 0L; + IfInfo[i].OLDmultircv = 0L; + IfInfo[i].brdcstxmt = 0L; + IfInfo[i].OLDbrdcstxmt = 0L; + IfInfo[i].brdcstrcv = 0L; + IfInfo[i].OLDbrdcstrcv = 0L; + NetDevCount = ++i; + + /* XXX: need sanity checks! */ + return( 0 ); +} + +/* + * getnetdevlist() -- get a list of all "up" interfaces + */ +int getnetdevlist( void ) { + + int fd; + int buffsize; + int prevsize; + int prevCount; + struct ifconf ifc; + struct ifreq *ifr; + + if( (fd = socket( PF_INET, SOCK_DGRAM, 0 )) < 0 ) { + return( -1 ); + } + + /* + * get the interface list via iotl( SIOCGIFCONF ) + * the following algorithm based on ideas from W.R. Stevens' + * "UNIX Network Programming", Vol. 1: + * Since the ioctl may return 0, indicating success, even if the + * ifreq buffer was too small, we have to make sure, it didn't + * get truncated by comparing our initial size guess with the + * actual returned size. + */ + prevsize = 0; + buffsize = NBUFFERS * sizeof( struct ifreq ); + while( 1 ) { + if( (ifc.ifc_buf = malloc( buffsize )) == NULL ) + return( -1 ); + + ifc.ifc_len = buffsize; + if( ioctl( fd, SIOCGIFCONF, &ifc ) < 0 ) { + if( errno != EINVAL || prevsize != 0 ) { + free( ifc.ifc_buf ); + return( -1 ); + } + } else { + if( ifc.ifc_len == prevsize ) + /* success */ + break; + prevsize = ifc.ifc_len; + } + /* + * initial buffer guessed too small, allocate a bigger one + */ + free( ifc.ifc_buf ); + buffsize = (NBUFFERS + 10) * sizeof( struct ifreq ); + } + + /* + * get the names for all interfaces which are configured "up" + * we're not interested in the ifc data (address), so we reuse the + * same structure (with ifc.len set) for the next ioctl() + */ + prevCount = NetDevCount; + for( ifr = (struct ifreq *) ifc.ifc_buf; + ifr < (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); + ifr++ ) { + if( ioctl( fd, SIOCGIFFLAGS, ifr ) < 0 ) { + free( ifc.ifc_buf ); + return( -1 ); + } + if( ifr->ifr_flags & IFF_UP ) + insertnetdev( ifr->ifr_name, ifr->ifr_flags ); + } + free( ifc.ifc_buf ); + close( fd ); + + if( (prevCount > 0) && (prevCount != NetDevCount) ) { + print_error( "RECONFIGURE\n" ); + prevCount = NetDevCount; + } + + return( NetDevCount ); +} + +void initNetDev( struct SensorModul* sm ) { +#ifdef HAVE_KSTAT + char mon[128]; + int i; + + getnetdevlist(); + for( i = 0; i < NetDevCount; i++ ) { + sprintf( mon, "network/%s/ipackets", IfInfo[i].Name ); + registerMonitor( mon, "integer", + printIPackets, printIPacketsInfo, sm ); + sprintf( mon, "network/%s/opackets", IfInfo[i].Name ); + registerMonitor( mon, "integer", + printOPackets, printOPacketsInfo, sm ); + /* + * if this isn't a loopback interface, + * register additional monitors + */ + if( ! (IfInfo[i].flags & IFF_LOOPBACK) ) { + /* + * recv errors + */ + sprintf( mon, "network/%s/ierrors", + IfInfo[i].Name ); + registerMonitor( mon, "integer", + printIErrors, printIErrorsInfo, sm ); + /* + * xmit errors + */ + sprintf( mon, "network/%s/oerrors", + IfInfo[i].Name ); + registerMonitor( mon, "integer", + printOErrors, printOErrorsInfo, sm ); + /* + * collisions + */ + sprintf( mon, "network/%s/collisions", + IfInfo[i].Name ); + registerMonitor( mon, "integer", + printCollisions, printCollisionsInfo, sm ); + /* + * multicast xmits + */ + sprintf( mon, "network/%s/multixmt", + IfInfo[i].Name ); + registerMonitor( mon, "integer", + printMultiXmits, printMultiXmitsInfo, sm ); + /* + * multicast recvs + */ + sprintf( mon, "network/%s/multircv", + IfInfo[i].Name ); + registerMonitor( mon, "integer", + printMultiRecvs, printMultiRecvsInfo, sm ); + /* + * broadcast xmits + */ + sprintf( mon, "network/%s/brdcstxmt", + IfInfo[i].Name ); + registerMonitor( mon, "integer", + printBcastXmits, printBcastXmitsInfo, sm ); + /* + * broadcast recvs + */ + sprintf( mon, "network/%s/brdcstrcv", + IfInfo[i].Name ); + registerMonitor( mon, "integer", + printBcastRecvs, printBcastRecvsInfo, sm ); + } + } +#endif +} + +void exitNetDev( void ) { +} + +int updateNetDev( void ) { + +#ifdef HAVE_KSTAT + kstat_ctl_t *kctl; + kstat_t *ksp; + kstat_named_t *kdata; + int i; + + /* + * get a kstat handle and update the user's kstat chain + */ + if( (kctl = kstat_open()) == NULL ) + return( 0 ); + while( kstat_chain_update( kctl ) != 0 ) + ; + + for( i = 0; i < NetDevCount; i++ ) { + char *name; + char *ptr; + + /* + * chop off the trailing interface no + */ + name = strdup( IfInfo[i].Name ); + ptr = name + strlen( name ) - 1; + while( (ptr > name) && isdigit( (int) *ptr ) ) { + *ptr = '\0'; + ptr--; + } + + /* + * traverse the kstat chain + * to find the appropriate statistics + */ + if( (ksp = kstat_lookup( kctl, + name, 0, IfInfo[i].Name )) == NULL ) { + free( name ); + return( 0 ); + } + if( kstat_read( kctl, ksp, NULL ) == -1 ) { + free( name ); + return( 0 ); + } + free( name ); + + /* + * lookup & store the data + */ + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "ipackets" ); + if( kdata != NULL ) { + IfInfo[i].OLDipackets = IfInfo[i].ipackets; + IfInfo[i].ipackets = kdata->value.ul; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "opackets" ); + if( kdata != NULL ) { + IfInfo[i].OLDopackets = IfInfo[i].opackets; + IfInfo[i].opackets = kdata->value.ul; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "ierrors" ); + if( kdata != NULL ) { + IfInfo[i].OLDierrors = IfInfo[i].ierrors; + IfInfo[i].ierrors = kdata->value.ul; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "oerrors" ); + if( kdata != NULL ) { + IfInfo[i].OLDoerrors = IfInfo[i].oerrors; + IfInfo[i].oerrors = kdata->value.ul; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "collisions" ); + if( kdata != NULL ) { + IfInfo[i].OLDcollisions = IfInfo[i].collisions; + IfInfo[i].collisions = kdata->value.ul; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "multixmt" ); + if( kdata != NULL ) { + IfInfo[i].OLDmultixmt = IfInfo[i].multixmt; + IfInfo[i].multixmt = kdata->value.ul; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "multircv" ); + if( kdata != NULL ) { + IfInfo[i].OLDmultircv = IfInfo[i].multircv; + IfInfo[i].multircv = kdata->value.ul; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "brdcstxmt" ); + if( kdata != NULL ) { + IfInfo[i].OLDbrdcstxmt = IfInfo[i].brdcstxmt; + IfInfo[i].brdcstxmt = kdata->value.ul; + } + kdata = (kstat_named_t *) kstat_data_lookup( ksp, "brdcstrcv" ); + if( kdata != NULL ) { + IfInfo[i].OLDbrdcstrcv = IfInfo[i].brdcstrcv; + IfInfo[i].brdcstrcv = kdata->value.ul; + } + } + + kstat_close( kctl ); +#endif /* ! HAVE_KSTAT */ + + return( 0 ); +} + +void printIPacketsInfo( const char *cmd ) { + fprintf(CurrentClient, "Received Packets\t0\t0\tPackets\n" ); +} + +void printIPackets( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDipackets > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].ipackets - IfInfo[i].OLDipackets); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} + +void printOPacketsInfo( const char *cmd ) { + fprintf(CurrentClient, "Transmitted Packets\t0\t0\tPackets\n" ); +} + +void printOPackets( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDopackets > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].opackets - IfInfo[i].OLDopackets ); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} + +void printIErrorsInfo( const char *cmd ) { + fprintf(CurrentClient, "Input Errors\t0\t0\tPackets\n" ); +} + +void printIErrors( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDierrors > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].ierrors - IfInfo[i].OLDierrors ); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} + +void printOErrorsInfo( const char *cmd ) { + fprintf(CurrentClient, "Output Errors\t0\t0\tPackets\n" ); +} + +void printOErrors( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDoerrors > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].oerrors - IfInfo[i].OLDoerrors ); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} + +void printCollisionsInfo( const char *cmd ) { + fprintf(CurrentClient, "Collisions\t0\t0\tPackets\n" ); +} + +void printCollisions( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDcollisions > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].collisions - IfInfo[i].OLDcollisions ); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} + +void printMultiXmitsInfo( const char *cmd ) { + fprintf(CurrentClient, "Multicasts Sent\t0\t0\tPackets\n" ); +} + +void printMultiXmits( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDmultixmt > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].multixmt - IfInfo[i].OLDmultixmt ); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} + +void printMultiRecvsInfo( const char *cmd ) { + fprintf(CurrentClient, "Multicasts Received\t0\t0\tPackets\n" ); +} + +void printMultiRecvs( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDmultircv > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].multircv - IfInfo[i].OLDmultircv ); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} + +void printBcastXmitsInfo( const char *cmd ) { + fprintf(CurrentClient, "Broadcasts Sent\t0\t0\tPackets\n" ); +} + +void printBcastXmits( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDbrdcstxmt > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].brdcstxmt - IfInfo[i].OLDbrdcstxmt ); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} + +void printBcastRecvsInfo( const char *cmd ) { + fprintf(CurrentClient, "Broadcasts Received\t0\t0\tPackets\n" ); +} + +void printBcastRecvs( const char *cmd ) { + + char *cmdcopy = strdup( cmd ); + char *name, *ptr; + int i; + + ptr = strchr( cmdcopy, (int) '/' ); + name = ++ptr; + ptr = strchr( name, (int) '/' ); + *ptr = '\0'; + + for( i = 0; i < NetDevCount; i++ ) { + if( (IfInfo[i].OLDbrdcstrcv > 0) + && (strcmp( IfInfo[i].Name, name ) == 0) ) { + fprintf(CurrentClient, "%ld\n", + IfInfo[i].brdcstrcv - IfInfo[i].OLDbrdcstrcv ); + free( cmdcopy ); + return; + } + } + free( cmdcopy ); + fprintf(CurrentClient, "0\n" ); +} diff --git a/ksysguard/ksysguardd/Tru64/NetDev.h b/ksysguard/ksysguardd/Tru64/NetDev.h new file mode 100644 index 000000000..b6ff54448 --- /dev/null +++ b/ksysguard/ksysguardd/Tru64/NetDev.h @@ -0,0 +1,59 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 Chris Schlaeger <cs@kde.org> + + Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + + 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 _NetDev_h_ +#define _NetDev_h_ + +void initNetDev(struct SensorModul* sm); +void exitNetDev(void); + +int updateNetDev(void); + +void printIPacketsInfo( const char *cmd ); +void printIPackets( const char *cmd ); + +void printOPacketsInfo( const char *cmd ); +void printOPackets( const char *cmd ); + +void printIErrorsInfo( const char *cmd ); +void printIErrors( const char *cmd ); + +void printOErrorsInfo( const char *cmd ); +void printOErrors( const char *cmd ); + +void printCollisionsInfo( const char *cmd ); +void printCollisions( const char *cmd ); + +void printMultiXmitsInfo( const char *cmd ); +void printMultiXmits( const char *cmd ); + +void printMultiRecvsInfo( const char *cmd ); +void printMultiRecvs( const char *cmd ); + +void printBcastXmitsInfo( const char *cmd ); +void printBcastXmits( const char *cmd ); + +void printBcastRecvsInfo( const char *cmd ); +void printBcastRecvs( const char *cmd ); + +#endif /* _NetDev_h */ diff --git a/ksysguard/ksysguardd/conf.c b/ksysguard/ksysguardd/conf.c new file mode 100644 index 000000000..1d857137b --- /dev/null +++ b/ksysguard/ksysguardd/conf.c @@ -0,0 +1,137 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "Command.h" + +#include "conf.h" + +CONTAINER LogFileList = 0; +CONTAINER SensorList = 0; +char* RegisterDomain = 0; + +void LogFileList_cleanup( void *ptr ); +void freeConfigFile( void ); + +void LogFileList_cleanup( void *ptr ) +{ + if ( ptr ) { + if ( ((ConfigLogFile*)ptr)->name ) + free( ((ConfigLogFile*)ptr)->name ); + + free( ptr ); + } +} + +void freeConfigFile( void ) +{ + destr_ctnr( LogFileList, LogFileList_cleanup ); + destr_ctnr( SensorList, free ); +} + +void parseConfigFile( const char *filename ) +{ + FILE* config; + char line[ 2048 ]; + char *begin, *token, *tmp; + ConfigLogFile *confLog; + + LogFileList = new_ctnr(); + SensorList = new_ctnr(); + + if ( ( config = fopen( filename, "r" ) ) == NULL ) { + log_error( "can't open config file '%s'", filename ); + + /** + If we can't open a config file we have to add the + available sensors manually + */ + push_ctnr( SensorList, strdup( "ProcessList" ) ); + push_ctnr( SensorList, strdup( "Memory" ) ); + push_ctnr( SensorList, strdup( "Stat" ) ); + push_ctnr( SensorList, strdup( "NetDev" ) ); + push_ctnr( SensorList, strdup( "NetStat" ) ); + push_ctnr( SensorList, strdup( "Apm" ) ); + push_ctnr( SensorList, strdup( "Acpi" ) ); + push_ctnr( SensorList, strdup( "CpuInfo" ) ); + push_ctnr( SensorList, strdup( "LoadAvg" ) ); + push_ctnr( SensorList, strdup( "LmSensors" ) ); + push_ctnr( SensorList, strdup( "DiskStat" ) ); + push_ctnr( SensorList, strdup( "LogFile" ) ); + push_ctnr( SensorList, strdup( "DellLaptop" ) ); + + return; + } + + while ( fgets( line, sizeof( line ), config ) != NULL ) { + if ( ( line[ 0 ] == '#') || ( strlen( line ) == 0 ) ) + continue; + + if ( strchr( line, '#' ) ) + *( strchr( line, '#' ) ) = '\0'; + + if ( line[ strlen( line ) - 1 ] == '\n' ) + line[ strlen( line ) - 1 ] = '\0'; + + if ( !strncmp( line, "RegisterDomain",14) && (begin = strchr( line, '=' )) ) RegisterDomain=strdup(begin+1); + + if ( !strncmp( line, "LogFiles", 8 ) && (begin = strchr( line, '=' )) ) { + begin++; + + for ( token = strtok( begin, "," ); token; token = strtok( NULL, "," ) ) { + if ( ( confLog = (ConfigLogFile *)malloc( sizeof( ConfigLogFile ) ) ) == NULL ) { + log_error( "malloc() no free memory avail" ); + continue; + } + confLog->name = strdup( token ); + tmp = strchr( confLog->name, ':' ); + *tmp = '\0'; + confLog->path = tmp; + confLog->path++; + + push_ctnr( LogFileList, confLog ); + } + } + + if ( !strncmp( line, "Sensors", 7 ) && (begin = strchr( line, '=' )) ) { + begin++; + + for ( token = strtok( begin, ","); token; token = strtok( NULL, "," ) ) + push_ctnr( SensorList, strdup( token ) ); + } + } + + fclose( config ); +} + +int sensorAvailable( const char *sensor ) +{ + char* name; + + for ( name = first_ctnr( SensorList ); name; name = next_ctnr( SensorList ) ) { + if ( !strcmp( name, sensor ) ) + return 1; + } + + return 0; +} diff --git a/ksysguard/ksysguardd/conf.h b/ksysguard/ksysguardd/conf.h new file mode 100644 index 000000000..40be01ea8 --- /dev/null +++ b/ksysguard/ksysguardd/conf.h @@ -0,0 +1,38 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 "ccont.h" + +#ifndef KSG_CONF_H +#define KSG_CONF_H + +typedef struct { + char *name; + char *path; +} ConfigLogFile; + +extern char* RegisterDomain; + +void parseConfigFile( const char *filename ); +void freeConfigFile(); + +int sensorAvailable( const char* sensor ); + +#endif diff --git a/ksysguard/ksysguardd/configure.in.in b/ksysguard/ksysguardd/configure.in.in new file mode 100644 index 000000000..9a2f748a1 --- /dev/null +++ b/ksysguard/ksysguardd/configure.in.in @@ -0,0 +1,45 @@ +#MIN_CONFIG + +AC_ARG_ENABLE(dnssd, [ --disable-dnssd don't require libdns_sd (browsing and publishing DNS-SD services will not be possible) ], with_dnssd=$enableval, with_dnssd=yes) +if test "$with_dnssd" = "yes"; then +AC_MSG_CHECKING(for DNS-SD support) +save_dnssdtest_LIBS="$LIBS" +save_dnssdtest_LDFLAGS="$LDFLAGS" +save_dnssdtest_CPPFLAGS="$CPPFLAGS" +LDFLAGS="$all_libraries $LDFLAGS" +CPPFLAGS="$CPPFLAGS $all_includes" +case $host_os in + darwin*) LIBS="" ;; + *) LIBS="-ldns_sd" ;; +esac +have_libdns_sd="no" +AC_TRY_LINK( [ + #include <dns_sd.h> + ],[ + DNSServiceRefDeallocate( (DNSServiceRef) 0); + TXTRecordDeallocate( (TXTRecordRef*) 0); + ],[ + AC_DEFINE(HAVE_DNSSD,1,[Define if dns-sd is available]) + case $host_os in + darwin*) LIB_DNSSD="" ;; + *) LIB_DNSSD="-ldns_sd" ;; + esac + have_libdns_sd="yes" + AC_MSG_RESULT(yes) + ],[ + AC_MSG_RESULT(no) + LIB_DNSSD="" +]) +CPPFLAGS=$save_dnssdtest_CPPFLAGS +LDFLAGS=$save_dnssdtest_LDFLAGS +LIBS=$save_dnssdtest_LIBS +fi + +case $host_os in + dragonfly*) LIB_KINFO="-lkinfo" ;; + *) LIB_KINFO="" ;; +esac + +AC_SUBST(LIB_DNSSD) +AC_SUBST(LIB_KINFO) +AM_CONDITIONAL(HAVE_DNSSD, test "$have_libdns_sd" = "yes") diff --git a/ksysguard/ksysguardd/ksysguardd.c b/ksysguard/ksysguardd/ksysguardd.c new file mode 100644 index 000000000..faea19492 --- /dev/null +++ b/ksysguard/ksysguardd/ksysguardd.c @@ -0,0 +1,633 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999 - 2003 Chris Schlaeger <cs@kde.org> + Tobias Koenig <tokoe@kde.org> + + Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 <config.h> +#include <ctype.h> +#include <fcntl.h> +#include <netdb.h> +#include <netinet/in.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/file.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <errno.h> +#include <../version.h> +#ifdef HAVE_DNSSD +#include <dns_sd.h> +#endif +#include "modules.h" + +#include "ksysguardd.h" + +#define CMDBUFSIZE 128 +#define MAX_CLIENTS 100 + +typedef struct { + int socket; + FILE* out; +} ClientInfo; + +static int ServerSocket; +static ClientInfo ClientList[ MAX_CLIENTS ]; +static int SocketPort = -1; +static unsigned char BindToAllInterfaces = 0; +static int CurrentSocket; +static const char *LockFile = "/var/run/ksysguardd.pid"; +static const char *ConfigFile = KSYSGUARDDRCFILE; +#ifdef HAVE_DNSSD +static int ServiceSocket = -1; +static DNSServiceRef Ref; +#endif + +void signalHandler( int sig ); +void makeDaemon( void ); +void resetClientList( void ); +int addClient( int client ); +int delClient( int client ); +int createServerSocket( void ); +#ifdef HAVE_DNSSD +void publish_callback (DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, + const char*, const char*, void *context); +#endif + +/** + This variable is set to 1 if a module requests that the daemon should + be terminated. + */ +int QuitApp = 0; + +/** + This variable indicates whether we are running as daemon or (1) or if + we were have a controlling shell. + */ +int RunAsDaemon = 0; + +/** + This pointer is used by all modules. It contains the file pointer of + the currently served client. This is stdout for non-daemon mode. + */ +FILE* CurrentClient = 0; + +static int processArguments( int argc, char* argv[] ) +{ + int option; + + opterr = 0; + while ( ( option = getopt( argc, argv, "-p:f:dih" ) ) != EOF ) { + switch ( tolower( option ) ) { + case 'p': + SocketPort = atoi( optarg ); + break; + case 'f': + ConfigFile = strdup( optarg ); + break; + case 'd': + RunAsDaemon = 1; + break; + case 'i': + BindToAllInterfaces = 1; + break; + case '?': + case 'h': + default: + fprintf(stderr, "Usage: %s [-d] [-i] [-p port]\n", argv[ 0 ] ); + return -1; + break; + } + } + + return 0; +} + +static void printWelcome( FILE* out ) +{ + fprintf( out, "ksysguardd %s\n" + "(c) 1999, 2000, 2001, 2002 Chris Schlaeger <cs@kde.org> and\n" + "(c) 2001 Tobias Koenig <tokoe@kde.org>\n" + "This program is part of the KDE Project and licensed under\n" + "the GNU GPL version 2. See http://www.kde.org for details.\n", + KSYSGUARD_VERSION ); + + fflush( out ); +} + +static int createLockFile() +{ + FILE *file; + + if ( ( file = fopen( LockFile, "w+" ) ) != NULL ) { + struct flock lock; + lock.l_type = F_WRLCK; + lock.l_whence = 0; + lock.l_start = 0; + lock.l_len = 0; + lock.l_pid = -1; + if ( fcntl( fileno( file ), F_SETLK, &lock ) < 0 ) { + if ( ( errno == EACCES ) || ( errno == EAGAIN ) ) { + log_error( "ksysguardd is running already" ); + fprintf( stderr, "ksysguardd is running already\n" ); + fclose( file ); + return -1; + } + } + + fseek( file, 0, SEEK_SET ); + fprintf( file, "%d\n", getpid() ); + fflush( file ); + ftruncate( fileno( file ), ftell( file ) ); + } else { + log_error( "Cannot create lockfile '%s'", LockFile ); + fprintf( stderr, "Cannot create lockfile '%s'\n", LockFile ); + return -2; + } + + /** + We abandon 'file' here on purpose. It's needed nowhere else, but we + have to keep the file open and locked. The kernel will remove the + lock when the process terminates and the runlevel scripts has to + remove the pid file. + */ + return 0; +} + +void signalHandler( int sig ) +{ + switch ( sig ) { + case SIGQUIT: + case SIGTERM: +#ifdef HAVE_DNSSD + if ( ServiceSocket != -1 ) DNSServiceRefDeallocate(Ref); +#endif + exit( 0 ); + break; + } +} + +static void installSignalHandler( void ) +{ + struct sigaction Action; + + Action.sa_handler = signalHandler; + sigemptyset( &Action.sa_mask ); + /* make sure that interrupted system calls are restarted. */ + Action.sa_flags = SA_RESTART; + sigaction( SIGTERM, &Action, 0 ); + sigaction( SIGQUIT, &Action, 0 ); +} + +static void dropPrivileges( void ) +{ + struct passwd *pwd; + + if ( ( pwd = getpwnam( "nobody" ) ) != NULL ) { + if ( !setgid(pwd->pw_gid) ) + setuid(pwd->pw_uid); + if (!geteuid() && getuid() != pwd->pw_uid) + _exit(1); + } + else { + log_error( "User 'nobody' does not exist." ); + /** + We exit here to avoid becoming vulnerable just because + user nobody does not exist. + */ + _exit(1); + } +} + +void makeDaemon( void ) +{ + int fd = -1; + switch ( fork() ) { + case -1: + log_error( "fork() failed" ); + break; + case 0: + setsid(); + chdir( "/" ); + umask( 0 ); + if ( createLockFile() < 0 ) + _exit( 1 ); + + dropPrivileges(); + installSignalHandler(); + + fd = open("/dev/null", O_RDWR, 0); + if (fd != -1) { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + close (fd); + } + break; + default: + exit( 0 ); + } +} + +static int readCommand( int fd, char* cmdBuf, size_t len ) +{ + unsigned int i; + char c; + for ( i = 0; i < len; ++i ) + { + int result = read( fd, &c, 1 ); + if (result < 0) + return -1; /* Error */ + + if (result == 0) { + if (i == 0) + return -1; /* Connection lost */ + + break; /* End of data */ + } + + if (c == '\n') + break; /* End of line */ + + cmdBuf[ i ] = c; + } + cmdBuf[i] = '\0'; + + return i; +} + +void resetClientList( void ) +{ + int i; + + for ( i = 0; i < MAX_CLIENTS; i++ ) { + ClientList[ i ].socket = -1; + ClientList[ i ].out = 0; + } +} + +/** + addClient adds a new client to the ClientList. + */ +int addClient( int client ) +{ + int i; + FILE* out; + + for ( i = 0; i < MAX_CLIENTS; i++ ) { + if ( ClientList[ i ].socket == -1 ) { + ClientList[ i ].socket = client; + if ( ( out = fdopen( client, "w+" ) ) == NULL ) { + log_error( "fdopen()" ); + return -1; + } + /* We use unbuffered IO */ + fcntl( fileno( out ), F_SETFL, O_NDELAY ); + ClientList[ i ].out = out; + printWelcome( out ); + fprintf( out, "ksysguardd> " ); + fflush( out ); + + return 0; + } + } + + return -1; +} + +/** + delClient removes a client from the ClientList. + */ +int delClient( int client ) +{ + int i; + + for ( i = 0; i < MAX_CLIENTS; i++ ) { + if ( ClientList[i].socket == client ) { + fclose( ClientList[ i ].out ); + ClientList[ i ].out = 0; + close( ClientList[ i ].socket ); + ClientList[ i ].socket = -1; + return 0; + } + } + + return -1; +} + +#ifdef HAVE_DNSSD +void publish_callback (DNSServiceRef ref, DNSServiceFlags f, DNSServiceErrorType errorCode, const char *name, + const char* type, const char* domain, void *context) +{ + if (errorCode != kDNSServiceErr_NoError) log_error("Publishing DNS-SD service failed with error %i",errorCode); +} +#endif + + +int createServerSocket() +{ + int i = 1; + int newSocket; + struct sockaddr_in s_in; + struct servent *service; + + if ( ( newSocket = socket( PF_INET, SOCK_STREAM, 0 ) ) < 0 ) { + log_error( "socket()" ); + return -1; + } + + setsockopt( newSocket, SOL_SOCKET, SO_REUSEADDR, &i, sizeof( i ) ); + + /** + The -p command line option always overrides the default or the + service entry. + */ + if ( SocketPort == -1 ) { + if ( ( service = getservbyname( "ksysguardd", "tcp" ) ) == NULL ) { + /** + No entry in service directory and no command line request, + so we take the build-in default (the offical IANA port). + */ + SocketPort = PORT_NUMBER; + } else + SocketPort = htons( service->s_port ); + } + + memset( &s_in, 0, sizeof( struct sockaddr_in ) ); + s_in.sin_family = AF_INET; + if ( BindToAllInterfaces ) + s_in.sin_addr.s_addr = htonl( INADDR_ANY ); + else + s_in.sin_addr.s_addr = htonl( INADDR_LOOPBACK ); + s_in.sin_port = htons( SocketPort ); + + if ( bind( newSocket, (struct sockaddr*)&s_in, sizeof( s_in ) ) < 0 ) { + log_error( "Cannot bind to port %d", SocketPort ); + return -1; + } + + if ( listen( newSocket, 5 ) < 0 ) { + log_error( "listen()" ); + return -1; + } + +#ifdef HAVE_DNSSD + if ( BindToAllInterfaces ) + if (DNSServiceRegister(&Ref, 0, 0, 0, "_ksysguard._tcp", RegisterDomain ? + RegisterDomain : "local.",NULL, htons(SocketPort), 0, 0, publish_callback, 0) == kDNSServiceErr_NoError) + ServiceSocket = DNSServiceRefSockFD(Ref); +#endif + + return newSocket; +} + +static int setupSelect( fd_set* fds ) +{ + int highestFD = ServerSocket; + FD_ZERO( fds ); + /** + Fill the filedescriptor array with all relevant descriptors. If we + not in daemon mode we only need to watch stdin. + */ + if ( RunAsDaemon ) { + int i; + FD_SET( ServerSocket, fds ); +#ifdef HAVE_DNSSD + if ( ServiceSocket != -1 ) { + FD_SET( ServiceSocket, fds ); + if ( highestFD < ServiceSocket) highestFD = ServiceSocket; + } +#endif + + for ( i = 0; i < MAX_CLIENTS; i++ ) { + if ( ClientList[ i ].socket != -1 ) { + FD_SET( ClientList[ i ].socket, fds ); + if ( highestFD < ClientList[ i ].socket ) + highestFD = ClientList[ i ].socket; + } + } + } else { + FD_SET( STDIN_FILENO, fds ); + if ( highestFD < STDIN_FILENO ) + highestFD = STDIN_FILENO; + } + + return highestFD; +} + +static void checkModules() +{ + struct SensorModul *entry; + + for ( entry = SensorModulList; entry->configName != NULL; entry++ ) + if ( entry->checkCommand != NULL && entry->available ) + entry->checkCommand(); +} + +static void handleTimerEvent( struct timeval* tv, struct timeval* last ) +{ + struct timeval now; + gettimeofday( &now, NULL ); + /* Check if the last event was really TIMERINTERVAL seconds ago */ + if ( now.tv_sec - last->tv_sec >= TIMERINTERVAL ) { + /* If so, update all sensors and save current time to last. */ + checkModules(); + *last = now; + } + /** + Set tv so that the next timer event will be generated in + TIMERINTERVAL seconds. + */ + tv->tv_usec = last->tv_usec - now.tv_usec; + if ( tv->tv_usec < 0 ) { + tv->tv_usec += 1000000; + tv->tv_sec = last->tv_sec + TIMERINTERVAL - 1 - now.tv_sec; + } else + tv->tv_sec = last->tv_sec + TIMERINTERVAL - now.tv_sec; +} + +static void handleSocketTraffic( int socketNo, const fd_set* fds ) +{ + char cmdBuf[ CMDBUFSIZE ]; + + if ( RunAsDaemon ) { + int i; + + if ( FD_ISSET( socketNo, fds ) ) { + int clientsocket; + struct sockaddr addr; + kde_socklen_t addr_len = sizeof( struct sockaddr ); + + /* a new connection */ + if ( ( clientsocket = accept( socketNo, &addr, &addr_len ) ) < 0 ) { + log_error( "accept()" ); + exit( 1 ); + } else + addClient( clientsocket ); + } + +#ifdef HAVE_DNSSD + if ( ServiceSocket != -1 && FD_ISSET( ServiceSocket, fds )) DNSServiceProcessResult(Ref); +#endif + + for ( i = 0; i < MAX_CLIENTS; i++ ) { + if ( ClientList[ i ].socket != -1 ) { + CurrentSocket = ClientList[ i ].socket; + if ( FD_ISSET( ClientList[ i ].socket, fds ) ) { + ssize_t cnt; + if ( ( cnt = readCommand( CurrentSocket, cmdBuf, sizeof( cmdBuf ) - 1 ) ) <= 0 ) + delClient( CurrentSocket ); + else { + cmdBuf[ cnt ] = '\0'; + if ( strncmp( cmdBuf, "quit", 4 ) == 0 ) + delClient( CurrentSocket ); + else { + CurrentClient = ClientList[ i ].out; + fflush( stdout ); + executeCommand( cmdBuf ); + fprintf( CurrentClient, "ksysguardd> " ); + fflush( CurrentClient ); + } + } + } + } + } + } else if ( FD_ISSET( STDIN_FILENO, fds ) ) { + if (readCommand( STDIN_FILENO, cmdBuf, sizeof( cmdBuf ) ) < 0) { + exit(0); + } + executeCommand( cmdBuf ); + printf( "ksysguardd> " ); + fflush( stdout ); + } +} + +static void initModules() +{ + struct SensorModul *entry; + + /* initialize all sensors */ + initCommand(); + + for ( entry = SensorModulList; entry->configName != NULL; entry++ ) { + if ( entry->initCommand != NULL && sensorAvailable( entry->configName ) ) { + entry->available = 1; + entry->initCommand( entry ); + } + } + + ReconfigureFlag = 0; +} + +static void exitModules() +{ + struct SensorModul *entry; + + for ( entry = SensorModulList; entry->configName != NULL; entry++ ) { + if ( entry->exitCommand != NULL && entry->available ) + entry->exitCommand(); + } + + exitCommand(); +} + +/* +================================ public part ================================= +*/ + +int main( int argc, char* argv[] ) +{ + fd_set fds; + struct timeval tv; + struct timeval last; + +#ifdef OSTYPE_FreeBSD + /** + If we are not root or the executable does not belong to the + kmem group, ksysguardd will crash because of permission problems + for opening /dev/kmem + */ + struct group* grentry = NULL; + + if ( geteuid() != 0 ) { + grentry = getgrnam( "kmem" ); + if ( grentry == NULL ) { + fprintf( stderr, "the group kmem is missing on your system\n" ); + return -1; + } + + if ( getegid() != grentry->gr_gid ) { + fprintf( stderr, "ksysguardd can't be started because of permission conflicts!\n" + "Start the program as user 'root' or change its group to 'kmem' and set the sgid-bit\n" ); + return -1; + } + + endgrent(); + } +#endif + + printWelcome( stdout ); + + if ( processArguments( argc, argv ) < 0 ) + return -1; + + parseConfigFile( ConfigFile ); + + initModules(); + + if ( RunAsDaemon ) { + makeDaemon(); + + if ( ( ServerSocket = createServerSocket() ) < 0 ) + return -1; + resetClientList(); + } else { + fprintf( stdout, "ksysguardd> " ); + fflush( stdout ); + CurrentClient = stdout; + ServerSocket = 0; + } + + tv.tv_sec = TIMERINTERVAL; + tv.tv_usec = 0; + gettimeofday( &last, NULL ); + + while ( !QuitApp ) { + int highestFD = setupSelect( &fds ); + /* wait for communication or timeouts */ + if ( select( highestFD + 1, &fds, NULL, NULL, &tv ) >= 0 ) { + handleTimerEvent( &tv, &last ); + handleSocketTraffic( ServerSocket, &fds ); + } + } + + exitModules(); + + freeConfigFile(); + + return 0; +} diff --git a/ksysguard/ksysguardd/ksysguardd.h b/ksysguard/ksysguardd/ksysguardd.h new file mode 100644 index 000000000..10184acd0 --- /dev/null +++ b/ksysguard/ksysguardd/ksysguardd.h @@ -0,0 +1,52 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 1999-2001 Chris Schlaeger <cs@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_KSYSGUARDD_H +#define KSG_KSYSGUARDD_H + +#include <stdio.h> +#include <time.h> + +/* This is the official ksysguardd port assigned by IANA. */ +#define PORT_NUMBER 3112 + +/* Timer interval for checking modules */ +#define TIMERINTERVAL 1 + +/* Timer interval for update modules */ +#define UPDATEINTERVAL 1 + +extern int RunAsDaemon; +extern int QuitApp; + +/* This pointer give you access to the client which made the request */ +extern FILE* CurrentClient; + +struct SensorModul { + const char *configName; + void (*initCommand)( struct SensorModul* ); + void (*exitCommand)( void ); + int (*updateCommand)( void ); + void (*checkCommand)( void ); + int available; + time_t time; +}; + +#endif diff --git a/ksysguard/ksysguardd/modules.h b/ksysguard/ksysguardd/modules.h new file mode 100644 index 000000000..5c214c7f0 --- /dev/null +++ b/ksysguard/ksysguardd/modules.h @@ -0,0 +1,151 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2001 Tobias Koenig <tokoe@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + 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 KSG_MODULES_H +#define KSG_MODULES_H + +#include "Command.h" +#include "conf.h" +#include "ksysguardd.h" + +#ifdef OSTYPE_Linux +#include "Memory.h" +#include "ProcessList.h" +#include "acpi.h" +#include "apm.h" +#include "cpuinfo.h" +#include "diskstat.h" +#include "i8k.h" +#include "lmsensors.h" +#include "loadavg.h" +#include "logfile.h" +#include "netdev.h" +#include "netstat.h" +#include "stat.h" +#endif /* OSTYPE_Linux */ + +#ifdef OSTYPE_FreeBSD +#include <grp.h> +#include "CPU.h" +#include "Memory.h" +#include "ProcessList.h" +#ifdef __i386__ +#include "apm.h" +#endif +#include "diskstat.h" +#include "loadavg.h" +#include "logfile.h" +#include "netdev.h" +#endif /* OSTYPE_FreeBSD */ + +#ifdef OSTYPE_Solaris +#include "LoadAvg.h" +#include "Memory.h" +#include "NetDev.h" +#include "ProcessList.h" +#endif /* OSTYPE_Solaris */ + +#ifdef OSTYPE_Irix +#include "LoadAvg.h" +#include "Memory.h" +#include "NetDev.h" +#include "ProcessList.h" +#include "cpu.h" +#endif /* OSTYPE_Irix */ + +#ifdef OSTYPE_Tru64 +#include "LoadAvg.h" +#include "Memory.h" +#include "NetDev.h" +#endif /* OSTYPE_Tru64 */ + +#ifdef OSTYPE_OpenBSD +#include "cpu.h" +#include "memory.h" +#endif /* OSTYPE_OpenBSD */ + +typedef void (*VSFunc)( struct SensorModul* ); +#define NULLVSFUNC ((VSFunc) 0) +typedef void (*VVFunc)( void ); +#define NULLVVFUNC ((VVFunc) 0) +typedef int (*IVFunc)( void ); +#define NULLIVFUNC ((IVFunc) 0) +#define NULLTIME ((time_t) 0) + +struct SensorModul SensorModulList[] = { +#ifdef OSTYPE_Linux + { "ProcessList", initProcessList, exitProcessList, updateProcessList, NULLVVFUNC, 0, NULLTIME }, + { "Memory", initMemory, exitMemory, updateMemory, NULLVVFUNC, 0, NULLTIME }, + { "Stat", initStat, exitStat, updateStat, NULLVVFUNC, 0, NULLTIME }, + { "NetDev", initNetDev, exitNetDev, updateNetDev, NULLVVFUNC, 0, NULLTIME }, + { "NetStat", initNetStat, exitNetStat, NULLIVFUNC, NULLVVFUNC, 0, NULLTIME }, + { "Apm", initApm, exitApm, updateApm, NULLVVFUNC, 0, NULLTIME }, + { "Acpi", initAcpi, exitAcpi, updateAcpi, NULLVVFUNC, 0, NULLTIME }, + { "CpuInfo", initCpuInfo, exitCpuInfo, updateCpuInfo, NULLVVFUNC, 0, NULLTIME }, + { "LoadAvg", initLoadAvg, exitLoadAvg, updateLoadAvg, NULLVVFUNC, 0, NULLTIME }, + { "LmSensors", initLmSensors, exitLmSensors, NULLIVFUNC, NULLVVFUNC, 0, NULLTIME }, + { "DiskStat", initDiskStat, exitDiskStat, updateDiskStat, checkDiskStat, 0, NULLTIME }, + { "LogFile", initLogFile, exitLogFile, NULLIVFUNC, NULLVVFUNC, 0, NULLTIME }, + { "DellLaptop", initI8k, exitI8k, updateI8k, NULLVVFUNC, 0, NULLTIME }, +#endif /* OSTYPE_Linux */ + +#ifdef OSTYPE_FreeBSD + { "CpuInfo", initCpuInfo, exitCpuInfo, updateCpuInfo, NULLVVFUNC, 0, NULLTIME }, + { "Memory", initMemory, exitMemory, updateMemory, NULLVVFUNC, 0, NULLTIME }, + { "ProcessList", initProcessList, exitProcessList, updateProcessList, NULLVVFUNC, 0, NULLTIME }, +#ifdef __i386__ + { "Apm", initApm, exitApm, updateApm, NULLVVFUNC, 0, NULLTIME }, +#endif + { "DiskStat", initDiskStat, exitDiskStat, updateDiskStat, checkDiskStat, 0, NULLTIME }, + { "LoadAvg", initLoadAvg, exitLoadAvg, updateLoadAvg, NULLVVFUNC, 0, NULLTIME }, + { "LogFile", initLogFile, exitLogFile, NULLIVFUNC, NULLVVFUNC, 0, NULLTIME }, + { "NetDev", initNetDev, exitNetDev, updateNetDev, checkNetDev, 0, NULLTIME }, +#endif /* OSTYPE_FreeBSD */ + +#ifdef OSTYPE_Solaris + { "LoadAvg", initLoadAvg, exitLoadAvg, updateLoadAvg, NULLVVFUNC, 0, NULLTIME }, + { "Memory", initMemory, exitMemory, updateMemory, NULLVVFUNC, 0, NULLTIME }, + { "NetDev", initNetDev, exitNetDev, updateNetDev, NULLVVFUNC, 0, NULLTIME }, + { "ProcessList", initProcessList, exitProcessList, updateProcessList, NULLVVFUNC, 0, NULLTIME }, +#endif /* OSTYPE_Solaris */ + +#ifdef OSTYPE_Irix + { "CpuInfo", initCpuInfo, exitCpuInfo, updateCpuInfo, NULLVVFUNC, 0, NULLTIME }, + { "LoadAvg", initLoadAvg, exitLoadAvg, updateLoadAvg, NULLVVFUNC, 0, NULLTIME }, + { "Memory", initMemory, exitMemory, updateMemory, NULLVVFUNC, 0, NULLTIME }, + { "NetDev", initNetDev, exitNetDev, updateNetDev, NULLVVFUNC, 0, NULLTIME }, + { "ProcessList", initProcessList, exitProcessList, updateProcessList, NULLVVFUNC, 0, NULLTIME }, +#endif /* OSTYPE_Irix */ + +#ifdef OSTYPE_Tru64 + { "LoadAvg", initLoadAvg, exitLoadAvg, updateLoadAvg, NULLVVFUNC, 0, NULLTIME }, + { "Memory", initMemory, exitMemory, updateMemory, NULLVVFUNC, 0, NULLTIME }, + { "NetDev", initNetDev, exitNetDev, updateNetDev, NULLVVFUNC, 0, NULLTIME }, +#endif /* OSTYPE_Tru64 */ + +#ifdef OSTYPE_OpenBSD + { "CpuInfo", initCpuInfo, exitCpuInfo, updateCpuInfo, NULLVVFUNC, 0, NULLTIME }, + { "Memory", initMemory, exitMemory, updateMemory, NULLVVFUNC, 0, NULLTIME }, +#endif /* OSTYPE_OpenBSD */ + + { NULL, NULLVSFUNC, NULLVVFUNC, NULLIVFUNC, NULLVVFUNC, 0, NULLTIME } +}; + +#endif diff --git a/ksysguard/pics/Makefile.am b/ksysguard/pics/Makefile.am new file mode 100644 index 000000000..040498488 --- /dev/null +++ b/ksysguard/pics/Makefile.am @@ -0,0 +1,5 @@ +#! /usr/bin/tail +2 +ksysguard_pics_datadir = $(kde_datadir)/ksysguard/pics + +ksysguard_pics_data_DATA = unknownapp.png ksysguardd.png computer.png daemon.png shell.png \ +kernel.png kdeapp.png X.png tools.png waiting.png running.png diff --git a/ksysguard/pics/X.png b/ksysguard/pics/X.png Binary files differnew file mode 100644 index 000000000..5b0742f87 --- /dev/null +++ b/ksysguard/pics/X.png diff --git a/ksysguard/pics/computer.png b/ksysguard/pics/computer.png Binary files differnew file mode 100644 index 000000000..85a078c13 --- /dev/null +++ b/ksysguard/pics/computer.png diff --git a/ksysguard/pics/daemon.png b/ksysguard/pics/daemon.png Binary files differnew file mode 100644 index 000000000..f21b3abfc --- /dev/null +++ b/ksysguard/pics/daemon.png diff --git a/ksysguard/pics/kdeapp.png b/ksysguard/pics/kdeapp.png Binary files differnew file mode 100644 index 000000000..629bfbc80 --- /dev/null +++ b/ksysguard/pics/kdeapp.png diff --git a/ksysguard/pics/kernel.png b/ksysguard/pics/kernel.png Binary files differnew file mode 100644 index 000000000..9e8c0d8dc --- /dev/null +++ b/ksysguard/pics/kernel.png diff --git a/ksysguard/pics/ksysguardd.png b/ksysguard/pics/ksysguardd.png Binary files differnew file mode 100644 index 000000000..ee4c6377d --- /dev/null +++ b/ksysguard/pics/ksysguardd.png diff --git a/ksysguard/pics/running.png b/ksysguard/pics/running.png Binary files differnew file mode 100644 index 000000000..543710fb7 --- /dev/null +++ b/ksysguard/pics/running.png diff --git a/ksysguard/pics/shell.png b/ksysguard/pics/shell.png Binary files differnew file mode 100644 index 000000000..d7c7bc271 --- /dev/null +++ b/ksysguard/pics/shell.png diff --git a/ksysguard/pics/tools.png b/ksysguard/pics/tools.png Binary files differnew file mode 100644 index 000000000..95bd319ce --- /dev/null +++ b/ksysguard/pics/tools.png diff --git a/ksysguard/pics/unknownapp.png b/ksysguard/pics/unknownapp.png Binary files differnew file mode 100644 index 000000000..2206448e4 --- /dev/null +++ b/ksysguard/pics/unknownapp.png diff --git a/ksysguard/pics/waiting.png b/ksysguard/pics/waiting.png Binary files differnew file mode 100644 index 000000000..2415dfc78 --- /dev/null +++ b/ksysguard/pics/waiting.png diff --git a/ksysguard/version.h b/ksysguard/version.h new file mode 100644 index 000000000..253a02fc7 --- /dev/null +++ b/ksysguard/version.h @@ -0,0 +1 @@ +#define KSYSGUARD_VERSION "1.2.0" |