diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-15 18:16:33 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-15 18:16:33 +0000 |
commit | ec0343ea3ec3c0eb444db2ba98f3c8dbe4cf156b (patch) | |
tree | 0f5c292df974170aaa5b91d8b09e3fa58a0b7c61 /kcpuload/kcpuload | |
download | kcpuload-ec0343ea3ec3c0eb444db2ba98f3c8dbe4cf156b.tar.gz kcpuload-ec0343ea3ec3c0eb444db2ba98f3c8dbe4cf156b.zip |
Added KDE3 version of kcpuload
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kcpuload@1090658 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kcpuload/kcpuload')
22 files changed, 2255 insertions, 0 deletions
diff --git a/kcpuload/kcpuload/Makefile.am b/kcpuload/kcpuload/Makefile.am new file mode 100644 index 0000000..b254d71 --- /dev/null +++ b/kcpuload/kcpuload/Makefile.am @@ -0,0 +1,49 @@ + +############################################################################ +# # +# Main KCPULoad sources. # +# # +# KCPULoad is copyright (c) 1999-2000, Markus Gustavsson # +# (c) 2002, Ben Burton # +# # +# 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. # +# # +############################################################################ + +INCLUDES = $(all_includes) + +bin_PROGRAMS = kcpuload + +kcpuload_LDFLAGS = $(KDE_RPATH) $(all_libraries) + +kcpuload_LDADD = $(LIB_KDEUI) + +kcpuload_SOURCES = \ + icontoggleaction.cpp \ + kcpudock.cpp \ + kcpuload.cpp \ + kcpuproc.cpp \ + main.cpp \ + statdock.cpp \ + speeddialog.cpp \ + statpopup.cpp + +noinst_HEADERS = \ + icontoggleaction.h \ + kcpudock.h \ + kcpuload.h \ + kcpuproc.h \ + speeddialog.h \ + statdock.h \ + statpopup.h + +METASOURCES = AUTO + +appsdir = $(kde_appsdir)/System +apps_DATA = kcpuload.desktop + +KDE_ICON = kcpuload + diff --git a/kcpuload/kcpuload/cr16-app-kcpuload.png b/kcpuload/kcpuload/cr16-app-kcpuload.png Binary files differnew file mode 100644 index 0000000..038a684 --- /dev/null +++ b/kcpuload/kcpuload/cr16-app-kcpuload.png diff --git a/kcpuload/kcpuload/cr32-app-kcpuload.png b/kcpuload/kcpuload/cr32-app-kcpuload.png Binary files differnew file mode 100644 index 0000000..e2679aa --- /dev/null +++ b/kcpuload/kcpuload/cr32-app-kcpuload.png diff --git a/kcpuload/kcpuload/cr48-app-kcpuload.png b/kcpuload/kcpuload/cr48-app-kcpuload.png Binary files differnew file mode 100644 index 0000000..7d7be85 --- /dev/null +++ b/kcpuload/kcpuload/cr48-app-kcpuload.png diff --git a/kcpuload/kcpuload/icontoggleaction.cpp b/kcpuload/kcpuload/icontoggleaction.cpp new file mode 100644 index 0000000..521a213 --- /dev/null +++ b/kcpuload/kcpuload/icontoggleaction.cpp @@ -0,0 +1,63 @@ + +/*************************************************************************** + * * + * KCPULoad and KNetLoad are copyright (c) 1999-2000, Markus Gustavsson * + * (c) 2002, Ben Burton * + * * + * 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. * + * * + ***************************************************************************/ + +#include "icontoggleaction.h" + +IconToggleAction::IconToggleAction( + const QString& useTextUnchecked, const QString& useIconUnchecked, + const QString& useTextChecked, const QString& useIconChecked, + const KShortcut& cut, const QObject* receiver, const char* slot, + QObject* parent, const char* name) : + KToggleAction(useTextUnchecked, useIconUnchecked, cut, receiver, + slot, parent, name), + textChecked(useTextChecked), textUnchecked(useTextUnchecked), + iconChecked(useIconChecked), iconUnchecked(useIconUnchecked) { +} + +IconToggleAction::IconToggleAction(const QString& useText, + const QString& useIconUnchecked, const QString& useIconChecked, + const KShortcut& cut, const QObject* receiver, const char* slot, + QObject* parent, const char* name) : + KToggleAction(useText, useIconUnchecked, cut, receiver, + slot, parent, name), + textChecked(useText), textUnchecked(useText), + iconChecked(useIconChecked), iconUnchecked(useIconUnchecked) { +} + +IconToggleAction::IconToggleAction( + const QString& useTextUnchecked, const QString& useIconUnchecked, + const QString& useTextChecked, const QString& useIconChecked, + const KShortcut& cut, QObject* parent, const char* name) : + KToggleAction(useTextUnchecked, useIconUnchecked, cut, parent, name), + textChecked(useTextChecked), textUnchecked(useTextUnchecked), + iconChecked(useIconChecked), iconUnchecked(useIconUnchecked) { +} + +IconToggleAction::IconToggleAction(const QString& useText, + const QString& useIconUnchecked, const QString& useIconChecked, + const KShortcut& cut, QObject* parent, const char* name) : + KToggleAction(useText, useIconUnchecked, cut, parent, name), + textChecked(useText), textUnchecked(useText), + iconChecked(useIconChecked), iconUnchecked(useIconUnchecked) { +} + +void IconToggleAction::setChecked(bool value) { + if (value != isChecked()) { + setText(value ? textChecked : textUnchecked); + setIcon(value ? iconChecked : iconUnchecked); + } + + KToggleAction::setChecked(value); +} + +#include "icontoggleaction.moc" diff --git a/kcpuload/kcpuload/icontoggleaction.h b/kcpuload/kcpuload/icontoggleaction.h new file mode 100644 index 0000000..469f763 --- /dev/null +++ b/kcpuload/kcpuload/icontoggleaction.h @@ -0,0 +1,61 @@ + +/*************************************************************************** + * * + * KCPULoad and KNetLoad are copyright (c) 1999-2000, Markus Gustavsson * + * (c) 2002, Ben Burton * + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef __ICONTOGGLEACTION_H +#define __ICONTOGGLEACTION_H + +#include <kaction.h> + +/** + * A toggle action that uses different labels and pixmaps in its + * different states. + */ +class IconToggleAction : public KToggleAction { + Q_OBJECT + + public: + /** + * Constructors. + */ + IconToggleAction( + const QString& useTextUnchecked, const QString& useIconUnchecked, + const QString& useTextChecked, const QString& useIconChecked, + const KShortcut& cut, const QObject* receiver, const char* slot, + QObject* parent, const char* name = 0); + IconToggleAction(const QString& useText, + const QString& useIconUnchecked, const QString& useIconChecked, + const KShortcut& cut, const QObject* receiver, const char* slot, + QObject* parent, const char* name = 0); + IconToggleAction( + const QString& useTextUnchecked, const QString& useIconUnchecked, + const QString& useTextChecked, const QString& useIconChecked, + const KShortcut& cut = KShortcut(), QObject* parent = 0, + const char* name = 0); + IconToggleAction(const QString& useText, + const QString& useIconUnchecked, const QString& useIconChecked, + const KShortcut& cut = KShortcut(), QObject* parent = 0, + const char* name = 0); + + /** + * Overridden to include icon adjustment. + */ + virtual void setChecked(bool); + + private: + QString textChecked, textUnchecked; + /**< The labels to use in the checked and unchecked states. */ + QString iconChecked, iconUnchecked; + /**< The icons to use in the checked and unchecked states. */ +}; + +#endif diff --git a/kcpuload/kcpuload/kcpudock.cpp b/kcpuload/kcpuload/kcpudock.cpp new file mode 100644 index 0000000..32352c3 --- /dev/null +++ b/kcpuload/kcpuload/kcpudock.cpp @@ -0,0 +1,32 @@ + +/*************************************************************************** + * * + * KCPULoad is copyright (c) 1999-2000, Markus Gustavsson * + * (c) 2002, Ben Burton * + * * + * 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. * + * * + ***************************************************************************/ + +#include "kcpudock.h" + +#include <klocale.h> + +KCPUDock::KCPUDock(int whichCPU, StatPopup *parent, const char *name) : + StatDock(whichCPU, i18n("C"), parent, name) { +} + +void KCPUDock::setCPULabel(int set) { + if (set == 1) + setLabel(i18n("C 0")); + else if (set == 2) + setLabel(i18n("C 1")); + else + setLabel(i18n("C")); + + repaint(); +} + diff --git a/kcpuload/kcpuload/kcpudock.h b/kcpuload/kcpuload/kcpudock.h new file mode 100644 index 0000000..f96e411 --- /dev/null +++ b/kcpuload/kcpuload/kcpudock.h @@ -0,0 +1,41 @@ + +/*************************************************************************** + * * + * KCPULoad is copyright (c) 1999-2000, Markus Gustavsson * + * (c) 2002, Ben Burton * + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef __KCPUDOCK_H +#define __KCPUDOCK_H + +#include "statdock.h" + +/** + * A KCPULoad system tray window for a specific CPU. + */ +class KCPUDock : public StatDock { + +public: + /** + * Constructor. + */ + KCPUDock(int whichDock, StatPopup *parent = 0, const char *name = 0); + + /** + * Sets the label for this diagram. The label will reflect which + * CPU the diagram represents. + * + * If multiple CPUs are not used, argument cpu should be 0. + * Otherwise argument cpu should be 1 or 2 for the first or second + * CPU respectively. + */ + void setCPULabel(int cpu); +}; + +#endif diff --git a/kcpuload/kcpuload/kcpuload.cpp b/kcpuload/kcpuload/kcpuload.cpp new file mode 100644 index 0000000..369ff69 --- /dev/null +++ b/kcpuload/kcpuload/kcpuload.cpp @@ -0,0 +1,177 @@ + +/*************************************************************************** + * * + * KCPULoad is copyright (c) 1999-2000, Markus Gustavsson * + * (c) 2002, Ben Burton * + * * + * 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. * + * * + ***************************************************************************/ + +#include "icontoggleaction.h" +#include "kcpudock.h" +#include "kcpuload.h" +#include "kcpuproc.h" + +#include <kaction.h> +#include <kconfig.h> +#include <klocale.h> +#include <kpopupmenu.h> + +KCPULoad::KCPULoad(QWidget *parent, const char *name) : + StatPopup(true, parent, name) { + // Create the /proc reading class and check for SMP. + proc = new KCPUProc(); + supportSMP = proc->hasSMP(); + + // Set up actions and read the config file. + setupActions(); + + // the vector must not be reallocated during resizing because the class + // that it contains (Reading) cannot be copied safely + r.reserve(proc->cpu.size()); + + // Create system tray windows. + resizeReadings(supportSMP && actSMP->isChecked() ? proc->cpu.size() : 1); + + // Initialise the pop-up window. + readPopupState(); + + // Off we go! + requestResize(); + if (isActive()) + startUpdates(); +} + +KCPULoad::~KCPULoad() { + delete proc; +} + +void KCPULoad::setSMP(bool set) { + if (! supportSMP) + return; + + resizeReadings(set ? proc->cpu.size() : 1); + + requestResize(); + if (isActive()) + takeReading(); + + config->setGroup("General Options"); + config->writeEntry("SMP", set); + config->sync(); +} + +QString KCPULoad::dockName(int which) const { + return i18n("CPU %1").arg(which+1); +} + +QColor KCPULoad::defaultDockColor(int which) const { + static const QColor c[] = { + QColor(0, 255, 0), + QColor(255, 0, 0), + QColor(255, 255, 0), + QColor(0, 255, 255) + }; + return c[which % (sizeof(c)/sizeof(c[0]))]; +} + +void KCPULoad::setupCustomActions() { + if (supportSMP) { + bool bVal = config->readBoolEntry("SMP", false); + actSMP = new IconToggleAction(i18n("Enable S&MP"), "smp", + i18n("S&MP Enabled"), "smpon", 0, coll, "smp"); + actSMP->setChecked(bVal); + connect(actSMP, SIGNAL(toggled(bool)), this, SLOT(setSMP(bool))); + } +} + +void KCPULoad::insertCustomItems(KPopupMenu* menu) { + if (supportSMP) { + actSMP->plug(menu); + menu->insertSeparator(); + } +} + +void KCPULoad::takeReadingInternal() { + proc->readLoad(); + + if (r.size() > 1) { + if (isSplit()) { + for (int i = 0; i < r.size(); i++) { + r[i].upper = proc->cpu[i].userPercent(); + r[i].lower = proc->cpu[i].systemPercent(); + } + } else { + for (int i = 0; i < r.size(); i++) { + r[i].upper = proc->cpu[i].totalPercent(); + } + } + } else if (r.size() > 0) { + if (isSplit()) { + r[0].upper = proc->all.userPercent(); + r[0].lower = proc->all.systemPercent(); + } else { + r[0].upper = proc->all.totalPercent(); + } + } + + if (isVisible()) { + if (r.size() > 1) { + if (isSplit()) { + QString user = + i18n("Current CPU User: %1%") + .arg(proc->all.userPercent()); + QString sys = + i18n("Current CPU System: %1%") + .arg(proc->all.systemPercent()); + for (int i = 0; i < r.size(); i++) { + user += i18n(", C%1: %2%").arg(i+1).arg(r[i].upper); + sys += i18n(", C%1: %2%").arg(i+1).arg(r[i].lower); + } + fullReading = i18n("%1.\n%2.").arg(user, sys); + } else { + QString total = + i18n("Current CPU usage: %1%") + .arg(proc->all.totalPercent()); + for (int i = 0; i < r.size(); i++) { + total += i18n(", C%1: %2%").arg(i+1).arg(r[i].upper); + } + fullReading = i18n("%1.").arg(total); + } + } else if (r.size() > 0) { + if (isSplit()) { + fullReading = i18n( + "Current CPU User: %1%.\n" + "Current CPU System: %2%.") + .arg(r[0].upper).arg(r[0].lower); + } else { + fullReading = i18n("Current CPU usage: %1%.").arg(r[0].upper); + } + } + } + } + +void KCPULoad::resizeReadings(int n) +{ + int i = r.size(); + r.resize(n); + for (; i < n; i++) { + // action is needed by KCPUDock constructor + r[i].Init(i, this); + KCPUDock* dock = new KCPUDock(i, this); + dock->setCPULabel(i+1); + r[i].dock = dock; + } + // special case single CPU or total + if (n == 1) { + static_cast<KCPUDock*>(r[0].dock)->setCPULabel(0); + } else if (n > 1) { + static_cast<KCPUDock*>(r[0].dock)->setCPULabel(1); + } +} + +#include "kcpuload.moc" diff --git a/kcpuload/kcpuload/kcpuload.desktop b/kcpuload/kcpuload/kcpuload.desktop new file mode 100644 index 0000000..96a909a --- /dev/null +++ b/kcpuload/kcpuload/kcpuload.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Application +Exec=kcpuload +Icon=kcpuload +DocPath=kcpuload/index.html +Terminal=0 +Name=KCPULoad +GenericName=CPU Monitor +Comment=A small CPU usage meter for Kicker +Categories=Qt;KDE;System diff --git a/kcpuload/kcpuload/kcpuload.h b/kcpuload/kcpuload/kcpuload.h new file mode 100644 index 0000000..f4ff85a --- /dev/null +++ b/kcpuload/kcpuload/kcpuload.h @@ -0,0 +1,71 @@ + +/*************************************************************************** + * * + * KCPULoad is copyright (c) 1999-2000, Markus Gustavsson * + * (c) 2002, Ben Burton * + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef __KCPULOAD_H +#define __KCPULOAD_H + +#include "statpopup.h" + +class KCPUProc; +class KToggleAction; + +/** + * The specific pop-up window used by KCPULoad. + */ +class KCPULoad : public StatPopup { + Q_OBJECT + +public: + /** + * Constructor and destructor. + */ + KCPULoad(QWidget *parent = 0, const char *name = 0); + ~KCPULoad(); + +public slots: + /** + * Slots for menu items. + */ + void setSMP(bool); + +protected: + /** + * Overrides from StatPopup. + */ + virtual QString dockName(int which) const; + virtual QColor defaultDockColor(int which) const; + virtual void setupCustomActions(); + virtual void insertCustomItems(KPopupMenu* menu); + virtual void takeReadingInternal(); + +private: + /** + * Changes the number of readings. + */ + void resizeReadings(int n); + + /** + * Reading raw CPU information. + */ + KCPUProc* proc; + /**< Used to obtain the raw information. */ + bool supportSMP; + /**< Does this system support SMP at all? */ + + /** + * Actions. + */ + KToggleAction* actSMP; +}; + +#endif diff --git a/kcpuload/kcpuload/kcpuproc.cpp b/kcpuload/kcpuload/kcpuproc.cpp new file mode 100644 index 0000000..7e5bc9b --- /dev/null +++ b/kcpuload/kcpuload/kcpuproc.cpp @@ -0,0 +1,196 @@ + +/*************************************************************************** + * * + * KCPULoad is copyright (c) 1999-2000, Markus Gustavsson * + * (c) 2002, Ben Burton * + * * + * 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. * + * * + ***************************************************************************/ + +#include "kcpuproc.h" + +#include <cstdlib> +#include <cstring> + +// BSD-specific includes. +#ifdef Q_OS_BSD4 +#include <sys/dkstat.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#include <string.h> +#include <kvm.h> +#ifdef Q_OS_NETBSD +#include <sys/sched.h> +#endif +#endif + +/** + * Linux + * ----- + * + * System information is read from /proc/stat. + * + * We assume /proc/stat is in one of the following formats: + * + * cpu %d %d %d %d + * .... + * + * cpu %d %d %d %d + * cpu0 %d %d %d %d + * .... + * + * cpu %d %d %d %d + * cpu0 %d %d %d %d + * cpu1 %d %d %d %d + * .... + * + * where each set of four numbers is of the form: + * + * user_ticks nice_ticks system_ticks idle_ticks + * + * We also allow sets of seven numbers instead of four (as provided by + * the 2.6 kernel); the last three of these numbers are ignored. + * + * BSD + * --- + * + * Currently only uni-processor mode is supported for BSD. + * + * BSD code by Andy Fawcett <andy@athame.co.uk> and + * Robbie Ward <linuxphreak@gmx.co.uk>, licensed under GPL2. + * + * Other Operating Systems + * ----------------------- + * + * Please, send in a patch! + * + * The KCPULoad maintainer is currently Ben Burton <bab@debian.org>, or + * you could submit a patch through the KDE bug tracking system + * (bugs.kde.org). + */ + +KCPUProc::CPU::Ticks::Ticks() : + U(0), S(0), N(0), I(0) +{ } + +KCPUProc::KCPUProc() { + smp = false; + + // Look for SMP support and take a current tick reading. + + // ========== BSD-specific (begin) ========== +#ifdef Q_OS_BSD4 + readLoad(); + return; +#endif + // ========== BSD-specific (end) ========== + + // ========== Linux-specific (begin) ========== +#ifdef Q_OS_LINUX + if ((fd = fopen("/proc/stat", "r")) == 0) + return; + + if (!all.parse(fd)) + return; + CPU c; + while (c.parse(fd)) + cpu.push_back(c); + smp = cpu.size() > 1; +#endif + // ========== Linux-specific (end) ========== +} + +void KCPUProc::readLoad() { + // OS-specific local variables. + + // ========== Linux-specific (begin) ========== +#ifdef Q_OS_LINUX + // Prepare to take the readings. + + if ((fd = fopen("/proc/stat", "r")) == 0) + return; + + // Take a fresh set of current readings (SMP mode). + + all.parse(fd); + for (int i = 0; i < cpu.size(); i++) { + if (!cpu[i].parse(fd)) + break; + } + + // Clean up after taking readings. + + fclose(fd); +#endif + // ========== Linux-specific (end) ========== + + // ========== BSD-specific (begin) ========== +#ifdef Q_OS_BSD4 + static int name2oid[2] = { 0, 3 }; + static int oidCpuTime[CTL_MAXNAME + 2]; + static size_t oidCpuTimeLen = sizeof(oidCpuTime); + long cpuTime[CPUSTATES]; + unsigned int cpuTimeLen = sizeof(cpuTime); + static char *name = "kern.cp_time"; + static int initialized = 0; + + if(smp) { + // Take a fresh set of current readings (SMP mode). + // TODO: Add SMP support for BSD. + } else { + // Take a fresh set of current readings (uni-processor mode). + + // The current readings must now become the previous readings. + all.p = all.c; + + if (! initialized) { + if (sysctl(name2oid, 2, oidCpuTime, &oidCpuTimeLen, name, + strlen(name)) < 0) + return; + + oidCpuTimeLen /= sizeof(int); + initialized = 1; + } + + if (sysctl(oidCpuTime, oidCpuTimeLen, cpuTime, &cpuTimeLen, 0, 0) < 0) + return; + + all.c.U = cpuTime[CP_USER]; + all.c.N = cpuTime[CP_NICE]; + all.c.S = cpuTime[CP_SYS]; + all.c.I = cpuTime[CP_IDLE]; + } +#endif + // ========== BSD-specific (end) ========== +} + +// ========== Linux-specific (begin) ========== +#ifdef Q_OS_LINUX +bool KCPUProc::CPU::parse(FILE* fd) { + char tagbuffer[32]; + Ticks n; // new ticks + if (fscanf(fd, "%32s%d%d%d%d", tagbuffer, &n.U, &n.N, &n.S, &n.I) != 5) { + return false; // failure + } + + if (strncmp(tagbuffer, "cpu", 3) != 0) { + return false; // tag mismatch + } + + // shift readings + p = c; + c = n; + + // ignore the rest of the line + int ch; + do { + ch = getc(fd); + } while (ch != '\n' && ch != EOF); + return true; +} +#endif +// ========== Linux-specific (end) ========== diff --git a/kcpuload/kcpuload/kcpuproc.h b/kcpuload/kcpuload/kcpuproc.h new file mode 100644 index 0000000..5631a72 --- /dev/null +++ b/kcpuload/kcpuload/kcpuproc.h @@ -0,0 +1,170 @@ + +/*************************************************************************** + * * + * KCPULoad is copyright (c) 1999-2000, Markus Gustavsson * + * (c) 2002, Ben Burton * + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef __KCPUPROC_H +#define __KCPUPROC_H + +#include <cstdio> +#include <qglobal.h> +#include <vector> + +/** + * A class used to read raw CPU load details from the system. + * + * See kcpuproc.cpp for details of supported operating systems. + */ +class KCPUProc { +public: + /** + * Constructor. + * + * In the constructor, a set of initial CPU tick readings are taken + * and SMP support is determined. + */ + KCPUProc(); + + /** + * Does this system appear to have SMP? + */ + bool hasSMP() const; + + /** + * Takes a fresh set of CPU tick readings. The numerical statistics + * returned refer to the time period between this reading and the + * previous (or between this reading and the object's construction + * if there was no previous reading). + */ + void readLoad(); + + /** + * Contains tick differences for a CPU. + */ + struct CPU { + /** + * Contains user/system/nice/idle tick readings. + */ + struct Ticks { + int U, S, N, I; + Ticks(); + /** Returns user ticks */ + int u() const { return U; } + /** Returns system ticks */ + int s() const { return S + N; } + /** Returns total (non-idle) ticks */ + int t() const { return U + S + N; } + /** Returns elapsed ticks */ + int e() const { return U + S + N + I; } + }; + + Ticks p; /**< The previous tick readings */ + Ticks c; /**< The last (most recent) tick readings */ + + /** + * The percentage of ticks between the last reading and the previous + * reading used by the user loop (compared to the nice, system and + * idle loops). + * + * This routine involves a short arithmetical calculation. + * If you're paranoid about running time, you might want to cache + * the result. + */ + int userPercent() const; + + /** + * The percentage of ticks between the last reading and the previous + * reading used by the system and nice loops (compared to the user and + * idle loops). + * + * This routine involves a short arithmetical calculation. + * If you're paranoid about running time, you might want to cache + * the result. + */ + int systemPercent() const; + + /** + * The percentage of ticks between the last reading and the previous + * reading used by the user, system and nice loops (compared to the + * idle loop). + * + * This routine involves a short arithmetical calculation. + * If you're paranoid about running time, you might want to cache + * the result. + */ + int totalPercent() const; + + /** + * OS-specific helper routines. + */ + + // ========== Linux-specific (begin) ========== +#ifdef Q_OS_LINUX + /** + * Parses the tick readings of the current line in #fd. + * The return value is \c false if the line does not begin with + * the tag "cpu" (optionally followed by a number). + * If the line can be parsed successfully, the last reading becomes + * the previous reading and the newly parsed reading becomes + * the last reading. + */ + bool parse(FILE* fd); +#endif + // ========== Linux-specific (end) ========== + }; + + /* + * Variables used in all modes. + */ + CPU all; /**< Tick readings for all CPUs. */ + + /* + * Variables used only with SMP. + */ + std::vector<CPU> cpu; /**< Tick readings for CPUs. */ + +private: + /* + * SMP support. + */ + bool smp; + /**< Does this system appear to have SMP? */ + + /** + * OS-specific data members. + */ + + // ========== Linux-specific (begin) ========== +#ifdef Q_OS_LINUX + FILE *fd; + /**< The file /proc/stat. */ +#endif + // ========== Linux-specific (end) ========== +}; + +inline bool KCPUProc::hasSMP() const { + return smp; +} + +inline int KCPUProc::CPU::userPercent() const { + int tot = c.e() - p.e(); + return (tot > 0 ? (100 * (c.u() - p.u())) / tot : 0); +} +inline int KCPUProc::CPU::systemPercent() const { + int tot = c.e() - p.e(); + return (tot > 0 ? (100 * (c.s() - p.s())) / tot : 0); +} +inline int KCPUProc::CPU::totalPercent() const { + int tot = c.e() - p.e(); + return (tot > 0 ? (100 * (c.t() - p.t())) / tot : 0); +} + +#endif diff --git a/kcpuload/kcpuload/lo16-app-kcpuload.png b/kcpuload/kcpuload/lo16-app-kcpuload.png Binary files differnew file mode 100644 index 0000000..edb85a8 --- /dev/null +++ b/kcpuload/kcpuload/lo16-app-kcpuload.png diff --git a/kcpuload/kcpuload/lo32-app-kcpuload.png b/kcpuload/kcpuload/lo32-app-kcpuload.png Binary files differnew file mode 100644 index 0000000..70f5459 --- /dev/null +++ b/kcpuload/kcpuload/lo32-app-kcpuload.png diff --git a/kcpuload/kcpuload/main.cpp b/kcpuload/kcpuload/main.cpp new file mode 100644 index 0000000..1be5ad3 --- /dev/null +++ b/kcpuload/kcpuload/main.cpp @@ -0,0 +1,64 @@ + +/*************************************************************************** + * * + * KCPULoad is copyright (c) 1999-2000, Markus Gustavsson * + * (c) 2002, Ben Burton * + * * + * 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. * + * * + ***************************************************************************/ + +#include "kcpuload.h" + +#include <kaboutdata.h> +#include <kcmdlineargs.h> +#include <klocale.h> +#include <kuniqueapplication.h> + +static const char *description = + I18N_NOOP("A small CPU usage meter for Kicker (the KDE panel)."); +static const char *message = + I18N_NOOP("KCPULoad was first released on the 8th of August, 1999."); +static const char *version = "2.00"; + +int main(int argc, char **argv) { + KAboutData aboutData("kcpuload", I18N_NOOP("KCPULoad"), version, + description, KAboutData::License_GPL, + "(c) 1999-2000, Markus Gustavsson\n" + "(c) 2002, Ben Burton\n" + "(c) 2009, Timothy Pearson", + message, 0 /* TODO: Website */, "bab@debian.org"); + + aboutData.addAuthor("Markus Gustavsson", "Original author", + "mighty@fragzone.se"); + aboutData.addAuthor("Ben Burton", "KDE3 rewrite, current maintainer", + "bab@debian.org"); + aboutData.addAuthor("Andy Fawcett", "BSD support", + "andy@athame.co.uk"); + aboutData.addAuthor("Robbie Ward", "BSD support", + "linuxphreak@gmx.co.uk"); + + aboutData.addCredit("Njaard, Charles Samuels", + "Support and help with KDE", "charles@kde.org"); + aboutData.addCredit("rikkus, Rik Hemsley", + "Support and help with KDE", "rik@kde.org"); + aboutData.addCredit("Mark Halpaap", + "Independent port to KDE3", "mark.halpaap@gmx.net"); + aboutData.addCredit("Thanks to everyone in #KDE OpenProjects for " + "being supportive and helpful!"); + + KCmdLineArgs::init(argc, argv, &aboutData); + KUniqueApplication::addCmdLineOptions(); + + if (! KUniqueApplication::start()) { + fprintf(stderr, I18N_NOOP("KCPULoad is already running!\n")); + return 1; + } + + KUniqueApplication app; + app.setMainWidget(new KCPULoad()); + return app.exec(); +} diff --git a/kcpuload/kcpuload/speeddialog.cpp b/kcpuload/kcpuload/speeddialog.cpp new file mode 100644 index 0000000..0d0588a --- /dev/null +++ b/kcpuload/kcpuload/speeddialog.cpp @@ -0,0 +1,63 @@ + +/*************************************************************************** + * * + * KCPULoad and KNetLoad are copyright (c) 1999-2000, Markus Gustavsson * + * (c) 2002, Ben Burton * + * * + * 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. * + * * + ***************************************************************************/ + +#include "speeddialog.h" + +#include <cstdlib> +#include <kcombobox.h> +#include <klocale.h> +#include <qlabel.h> +#include <qhbox.h> +#include <qvalidator.h> + +static int stockSpeed[] = { + 100, 150, 200, 250, 300, 400, 600, 800, 1000, 1200, 1500, 2000, 2500, + 3000, 4000, 5000, 0 +}; + +SpeedDialog::SpeedDialog(int defaultSpeed, QWidget* parent) : + KDialogBase(parent, "speed dialog", true, + i18n("Select Speed"), Ok|Cancel, Ok), + speed(defaultSpeed) { + QHBox* page = makeHBoxMainWidget(); + + new QLabel(i18n("Update interval in milliseconds:"), page); + + KComboBox* speedBox = new KComboBox(true, page); + + QIntValidator* val = new QIntValidator(this); + val->setBottom(1); + speedBox->setValidator(val); + + QString speedStr; + for (int i = 0; stockSpeed[i]; i++) { + speedStr.setNum(stockSpeed[i]); + speedBox->insertItem(speedStr); + } + + speedStr.setNum(defaultSpeed); + speedBox->setCurrentText(speedStr); + + connect(speedBox, SIGNAL(textChanged(const QString&)), + this, SLOT(updateSpeed(const QString&))); +} + +int SpeedDialog::getSpeed() const { + return speed; +} + +void SpeedDialog::updateSpeed(const QString& text) { + speed = atoi(text.ascii()); +} + +#include "speeddialog.moc" diff --git a/kcpuload/kcpuload/speeddialog.h b/kcpuload/kcpuload/speeddialog.h new file mode 100644 index 0000000..491a6be --- /dev/null +++ b/kcpuload/kcpuload/speeddialog.h @@ -0,0 +1,49 @@ + +/*************************************************************************** + * * + * KCPULoad and KNetLoad are copyright (c) 1999-2000, Markus Gustavsson * + * (c) 2002, Ben Burton * + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef __SPEEDDIALOG_H +#define __SPEEDDIALOG_H + +#include <kdialogbase.h> + +/** + * A dialog used to select the update speed for a StatPopup. + */ +class SpeedDialog : public KDialogBase { + Q_OBJECT + + public: + /** + * Constructor. + */ + SpeedDialog(int defaultSpeed, QWidget* parent); + + /** + * Returns the speed currently selected in the dialog. + * This is valid after the dialog has closed. + */ + int getSpeed() const; + + private slots: + /** + * Updates the speed variable to reflect the latest changes in + * the speed combo box. + */ + virtual void updateSpeed(const QString&); + + private: + int speed; + /**< The speed currently selected in the speed combo box. */ +}; + +#endif diff --git a/kcpuload/kcpuload/statdock.cpp b/kcpuload/kcpuload/statdock.cpp new file mode 100644 index 0000000..95a13c5 --- /dev/null +++ b/kcpuload/kcpuload/statdock.cpp @@ -0,0 +1,244 @@ + +/*************************************************************************** + * * + * KCPULoad and KNetLoad are copyright (c) 1999-2000, Markus Gustavsson * + * (c) 2002, Ben Burton * + * * + * 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. * + * * + ***************************************************************************/ + +#include "statdock.h" +#include "statpopup.h" +#include <qpainter.h> + +const int StatDock::fillLines = 0; +const int StatDock::fillBars = 1; +const int StatDock::fillShaded = 2; + +const QColor StatDock::colorGrid(120, 120, 120); +const QColor StatDock::colorGridInactive(60, 60, 60); +const QColor StatDock::colorLabel(255, 255, 255); +const QColor StatDock::colorLabelInactive(125, 125, 125); +const QColor StatDock::colorLower(255, 255, 255); +const QColor StatDock::colorLowerInactive(125, 125, 125); +const QColor StatDock::colorBlack(0, 0, 0); + +#define DOCK_SIZE 24 +#define DOCK_SCALE 4.34783 // Approx. 100/23. +#define SOFT_STEP 3 + +StatDock::StatDock(int whichDock, const QString& useLabel, + StatPopup *parent, const char *name) : + KSystemTray(parent,name), + label(useLabel), + bufUpper(new int[DOCK_SIZE]), + bufLower(new int[DOCK_SIZE]), + pos(0) { + // Initialise the stored readings. + for (i = 0; i < DOCK_SIZE; i++) + bufUpper[i] = bufLower[i] = 0; + + // Initialise the display. + parent->initDock(this, contextMenu(), whichDock); + setBackgroundColor(colorBlack); + resize(24, 24); + show(); +} + +StatDock::~StatDock() { + delete[] bufUpper; + delete[] bufLower; +} + +void StatDock::setGrid(bool set) { + grid = set; + repaint(); +} + +void StatDock::setActive(bool set) { + active = set; + repaint(); +} + +void StatDock::setSoft(bool set) { + soft = set; + repaint(); +} + +void StatDock::setSplit(bool set) { + split = set; + repaint(); +} + +void StatDock::setLabelled(bool set) { + labelled = set; + repaint(); +} + +void StatDock::setLabel(const QString& set) { + label = set; + repaint(); +} + +void StatDock::setFill(int set) { + fill = set; + repaint(); +} + +void StatDock::setColor(const QColor& set) { + colorUpper = set; + colorUpperInactive = colorUpper.dark(); + repaint(); +} + +void StatDock::clearHistory(void) { + for (i = 0; i < DOCK_SIZE; i++) + bufUpper[i] = bufLower[i] = 0; + repaint(); +} + +void StatDock::addPercentReading(int upper, int lower) { + // Rescale the readings to a measure in pixels. + upper = (int) (((float) upper) / DOCK_SCALE); + lower = (split ? (int) (((float) lower) / DOCK_SCALE) : 0); + + if (soft) { + // Do a bit of juggling to obtain a soft reading. + oldUpper = bufUpper[pos]; + oldLower = bufLower[pos]; + if(++pos >= DOCK_SIZE) + pos = 0; + + // Modify the upper reading. + if (upper > oldUpper + SOFT_STEP) + upper = oldUpper + SOFT_STEP; + else if (upper < oldUpper - SOFT_STEP) + upper = oldUpper - SOFT_STEP; + bufUpper[pos] = upper; + + // Modify the lower reading. + if (split) { + if (lower > oldLower + SOFT_STEP) + lower = oldLower + SOFT_STEP; + else if (lower < oldLower - SOFT_STEP) + lower = oldLower - SOFT_STEP; + } + bufLower[pos] = lower; + } else { + // Just a straight update. + if(++pos >= DOCK_SIZE) + pos = 0; + bufUpper[pos] = upper; + bufLower[pos] = lower; + } + + // Refresh the diagram. + repaint(); +} + +void StatDock::paintEvent(QPaintEvent*) { + QPainter p(this); + + // Start by drawing the grid. + if(grid) { + p.setPen((active) ? colorGrid : colorGridInactive); + p.drawLine(0, 4, 23, 4); + p.drawLine(0, 9, 23, 9); + p.drawLine(0, 14, 23, 14); + p.drawLine(0, 19, 23, 19); + } + + if(fill == fillShaded) { + // Shaded + for(i = 0; i < 24; i++) { + tmpPos = (pos + i + 1) % DOCK_SIZE; + for(j = 0; j <= bufUpper[tmpPos]; j++) { + if (bufUpper[tmpPos] == 0 || j == 0) + p.setPen(colorBlack); + else if (active) + p.setPen(colorUpper.dark((100 * bufUpper[tmpPos]) / j)); + else + p.setPen(colorUpper.dark((200 * bufUpper[tmpPos]) / j)); + + if(split) + p.drawPoint(i, DOCK_SIZE - 1 - j - bufLower[tmpPos]); + else + p.drawPoint(i, DOCK_SIZE - j); + } + + if(split) { + for(j = 0; j <= bufLower[tmpPos]; j++) { + if (bufLower[tmpPos] == 0 || j == 0) + p.setPen(colorBlack); + else if (active) + p.setPen(colorLower.dark((100 * bufLower[tmpPos]) / j)); + else + p.setPen(colorLower.dark((200 * bufLower[tmpPos]) / j)); + + p.drawPoint(i, 23 - j); + } + } + } + } else if (fill == fillBars) { + // Bars + if(split) { + // Draw the upper bars, then the lower to save on pen + // adjustments. + p.setPen(active ? colorUpper : colorUpperInactive); + for(i = 0; i < 24; i++) { + tmpPos = (pos + i + 1) % DOCK_SIZE; + p.drawLine(i, DOCK_SIZE - 1 - bufUpper[tmpPos] - + bufLower[tmpPos], i, DOCK_SIZE - 1 - bufLower[tmpPos]); + } + p.setPen(active ? colorLower : colorLowerInactive); + for(i = 0; i < 24; i++) { + tmpPos = (pos + i + 1) % DOCK_SIZE; + p.drawLine(i, DOCK_SIZE - 1 - bufLower[tmpPos], + i, DOCK_SIZE - 1); + } + } else { + p.setPen(active ? colorUpper : colorUpperInactive); + for(i = 0; i < 24; i++) { + tmpPos = (pos + i + 1) % DOCK_SIZE; + p.drawLine(i, DOCK_SIZE - 1 - bufUpper[tmpPos], + i, DOCK_SIZE - 1); + } + } + } else { + // Lines + if(split) { + // Draw the upper line, then the lower to save on pen + // adjustments. + p.setPen(active ? colorUpper : colorUpperInactive); + for(i = 0; i < 24; i++) { + tmpPos = (pos + i + 1) % DOCK_SIZE; + p.drawPoint(i, DOCK_SIZE - 1 - + bufUpper[tmpPos] - bufLower[tmpPos]); + } + p.setPen(active ? colorLower : colorLowerInactive); + for(i = 0; i < 24; i++) { + tmpPos = (pos + i + 1) % DOCK_SIZE; + p.drawPoint(i, DOCK_SIZE - 1 - bufLower[tmpPos]); + } + } else { + p.setPen(active ? colorUpper : colorUpperInactive); + for(i = 0; i < 24; i++) { + tmpPos = (pos + i + 1) % DOCK_SIZE; + p.drawPoint(i, DOCK_SIZE - 1 - bufUpper[tmpPos]); + } + } + } + + // Finally label the diagrams. + if(labelled) { + p.setFont(QFont("Helvetica", 8)); + p.setPen((active) ? colorLabel : colorLabelInactive); + p.drawText(rect(), AlignLeft | AlignTop, label); + } +} + +#include "statdock.moc" diff --git a/kcpuload/kcpuload/statdock.h b/kcpuload/kcpuload/statdock.h new file mode 100644 index 0000000..a9eb256 --- /dev/null +++ b/kcpuload/kcpuload/statdock.h @@ -0,0 +1,160 @@ + +/*************************************************************************** + * * + * KCPULoad and KNetLoad are copyright (c) 1999-2000, Markus Gustavsson * + * (c) 2002, Ben Burton * + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef __STATDOCK_H +#define __STATDOCK_H + +#include <qcolor.h> +#include <ksystemtray.h> + +class StatPopup; + +/** + * A system tray window that displays a recent history of readings. + * A single application might have many of these windows. + * + * Two simultaneous sets of readings are supported; these will be + * referred to as upper and lower readings. When diagram splitting is + * switched on, these readings will be displayed together on the diagram + * with the upper readings shown above the lower readings. When diagram + * splitting is switched off, only the upper readings will be displayed. + * + * The parent window of a StatDock must be a StatPopup, which provides + * all of the actions in this window's context menu. + */ +class StatDock : public KSystemTray { + Q_OBJECT + +public: + /** + * Fill style constants. + */ + static const int fillLines; + static const int fillBars; + static const int fillShaded; + + /** + * Colour constants. + */ + static const QColor colorGrid; + static const QColor colorGridInactive; + static const QColor colorLabel; + static const QColor colorLabelInactive; + static const QColor colorLower; + static const QColor colorLowerInactive; + static const QColor colorBlack; + +public: + /** + * Constructor and destructor. + * + * Note that the constructor will call parent->initDock(). + * + * Parameter whichDock must be 0 or 1 to specify whether this dock + * will become dock[0] or dock[1] in the given StatPopup parent. + * Parameter useLabel should contain the label that will be drawn on + * the diagram if labelling is enabled. + */ + StatDock(int whichDock, const QString& useLabel, StatPopup *parent, + const char *name = 0); + ~StatDock(); + + /** + * Setting display options. + */ + void setGrid(bool); + void setActive(bool); + void setSoft(bool); + void setSplit(bool); + void setLabelled(bool); + void setLabel(const QString&); + void setFill(int); + void setColor(const QColor&); + +public slots: + /** + * Clear the history of recent readings. + * All readings will be reset to zero and the diagram will be + * updated. + */ + void clearHistory(); + + /** + * Add the given pair of readings as the most recent in our list. + * The diagram will be updated accordingly. + * + * Each argument should be a percentage between 0 and 100. + * The sum of both arguments must not exceed 100. + * + * If diagram splitting is switched off, the given lower reading + * will be ignored completely and 0 will be used instead. + * + * @param upper the upper reading in this pair. + * @param lower the lower reading in this pair. + */ + void addPercentReading(int upper, int lower); + +private: + /** + * Repaint this system tray window with a fresh diagram. + */ + void paintEvent(QPaintEvent*); + +private: + /** + * Display options. + */ + bool grid; + /**< Should the grid be displayed behind the diagram? */ + bool active; + /**< Is this meter currently active? */ + bool soft; + /**< Are we artificially modifying the readings to produce a + soft curve? */ + bool split; + /**< Are we displaying both upper and lower readings? */ + bool labelled; + /**< Should this diagram be labelled? */ + QString label; + /**< The specific label to draw on this diagram. */ + int fill; + /**< Specifies which of the predefined fill styles to use. */ + QColor colorUpper; + /**< Colour for displaying the upper readings. */ + QColor colorUpperInactive; + /**< Colour for displaying the upper readings whilst the diagram + is inactive. */ + + /** + * Stored readings. + */ + int* bufUpper; + /**< Stores our list of recent upper readings. + This list begins at index (pos + 1) as the earliest reading + and cycles around to index (pos) as the latest reading. */ + int* bufLower; + /**< Stores our list of recent lower readings. + This list begins at index (pos + 1) as the earliest reading + and cycles around to index (pos) as the latest reading. */ + int pos; + /**< The index in our arrays of the most recent reading. */ + + + /** + * Temporaries. + */ + int i, j, tmpPos, oldUpper, oldLower; + /**< Temporary variables used during computations. */ +}; + +#endif diff --git a/kcpuload/kcpuload/statpopup.cpp b/kcpuload/kcpuload/statpopup.cpp new file mode 100644 index 0000000..f6e7b4d --- /dev/null +++ b/kcpuload/kcpuload/statpopup.cpp @@ -0,0 +1,485 @@ + +/*************************************************************************** + * * + * KCPULoad and KNetLoad are copyright (c) 1999-2000, Markus Gustavsson * + * (c) 2002, Ben Burton * + * * + * 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. * + * * + ***************************************************************************/ + +#include "icontoggleaction.h" +#include "speeddialog.h" +#include "statdock.h" +#include "statpopup.h" + +#include <qpainter.h> +#include <qtimer.h> +#include <kaction.h> +#include <kcolordialog.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kpopupmenu.h> +#include <kwin.h> +#include <cstdlib> + +#define DEFAULT_SPEED 1000 +#define TEXT_EXPANSION_HORIZONTAL 10 +#define TEXT_EXPANSION_VERTICAL 3 + +const QColor StatPopup::colorBorder(0, 0, 0); + +StatPopup::Reading::Reading() : + dock(0), + actColor(0) +{ } + +StatPopup::Reading::~Reading() +{ + delete actColor; + delete dock; +} + +void StatPopup::Reading::Init(int which, StatPopup* popup) +{ + char colorid[30]; + sprintf(colorid, "Color%d", which); + + color = popup->defaultDockColor(which); + color = popup->config->readColorEntry(colorid, &color); + actColor = new KAction(i18n("Color (%1)...").arg(popup->dockName(which)), + "color", 0, popup, SLOT(selectColor()), popup->coll, colorid); +} + + +StatPopup::StatPopup(bool useSupportSplit, QWidget *parent, const char *name) : + QWidget(parent, name, Qt::WStyle_Customize | Qt::WStyle_NoBorder | + Qt::WStyle_StaysOnTop | Qt::WDestructiveClose | Qt::WType_TopLevel), + supportSplit(useSupportSplit) { + // Window management. + KWin::setState(winId(), NET::SkipTaskbar | NET::SkipPager); + + // TODO: Get all-desktops working, even after a hide/reshow. + //KWin::setOnAllDesktops(winId(), true); + + // Basic variable initialisation. + relX = relY = 0; + isDragged = closing = false; + + // Initialise the text contents of this pop-up. + fullReading = i18n("Inactive."); + resizeToText(); + + // Prepare for actions and the config file, but don't actually add + // any actions or read the configuration. + config = KGlobal::config(); + coll = new KActionCollection(this); + + // Set up a timer for our periodic updates. + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(takeReading())); +} + +StatPopup::~StatPopup() { +} + +void StatPopup::readPopupState() { + config->setGroup("Popup Options"); + + // Read the position. + int useX = config->readNumEntry("PopupX", 0); + int useY = config->readNumEntry("PopupY", 0); + if (useX || useY) + move(useX, useY); + + // Show the pop-up if appropriate. + if (config->readBoolEntry("PopupActive", false)) + show(); + else + hide(); +} + +void StatPopup::savePopupState() { + config->setGroup("Popup Options"); + config->writeEntry("PopupActive", isVisible()); + config->writeEntry("PopupX", x()); + config->writeEntry("PopupY", y()); + config->sync(); +} + +void StatPopup::initDock(StatDock* target, KPopupMenu* menu, int whichDock) { + // Initialise the menus. + actActive->plug(menu); + actClearHistory->plug(menu); + menu->insertSeparator(); + actSpeed->plug(menu); + if (supportSplit) + actSplit->plug(menu); + menu->insertSeparator(); + + insertCustomItems(menu); + + KPopupMenu* fillMenu = new KPopupMenu(menu); + actFillLines->plug(fillMenu); + actFillBars->plug(fillMenu); + actFillShaded->plug(fillMenu); + menu->insertItem(SmallIcon("style"), i18n("St&yle"), fillMenu); + + actSoft->plug(menu); + actLabelled->plug(menu); + actGrid->plug(menu); + r[whichDock].actColor->plug(menu); + menu->insertSeparator(); + menu->insertItem(SmallIcon("help"), i18n("&Help"), + (new KHelpMenu(0, KGlobal::instance()->aboutData(), false))->menu()); + + // Set up display properties for the dock. + target->setActive(actActive->isChecked()); + target->setSplit(isSplit()); + target->setFill(fillStyle); + target->setSoft(actSoft->isChecked()); + target->setLabelled(actLabelled->isChecked()); + target->setGrid(actGrid->isChecked()); + target->setColor(r[whichDock].color); + setCustomProperties(target); +} + +bool StatPopup::isActive() const { + return actActive->isChecked(); +} + +bool StatPopup::isSplit() const { + return (supportSplit ? actSplit->isChecked() : false); +} + +void StatPopup::setActive(bool set) { + if (set) + startUpdates(); + else + stopUpdates(); + + for (int i = 0; i < r.size(); i++) { + r[i].dock->setActive(set); + } + + config->setGroup("General Options"); + config->writeEntry("Active", set); + config->sync(); +} + +void StatPopup::clearHistory() { + for (int i = 0; i < r.size(); i++) { + r[i].dock->clearHistory(); + } +} + +void StatPopup::selectSpeed() { + SpeedDialog dlg(speed, firstDock()); + if (dlg.exec()) { + int newSpeed = dlg.getSpeed(); + if (newSpeed > 0) { + speed = newSpeed; + if (timer->isActive()) + timer->changeInterval(speed); + + config->setGroup("General Options"); + config->writeEntry("Speed", speed); + config->sync(); + } + } +} + +void StatPopup::setSplit(bool set) { + if (! supportSplit) + return; + + for (int i = 0; i < r.size(); i++) { + r[i].dock->setSplit(set); + } + + requestResize(); + + config->setGroup("General Options"); + config->writeEntry("Split", set); + config->sync(); +} + +void StatPopup::setFillLines() { + fillStyle = StatDock::fillLines; + + actFillLines->setChecked(true); + actFillBars->setChecked(false); + actFillShaded->setChecked(false); + + for (int i = 0; i < r.size(); i++) { + r[i].dock->setFill(StatDock::fillLines); + } + + config->setGroup("General Options"); + config->writeEntry("StyleID", StatDock::fillLines); + config->sync(); +} + +void StatPopup::setFillBars() { + fillStyle = StatDock::fillBars; + + actFillLines->setChecked(false); + actFillBars->setChecked(true); + actFillShaded->setChecked(false); + + for (int i = 0; i < r.size(); i++) { + r[i].dock->setFill(StatDock::fillBars); + } + + config->setGroup("General Options"); + config->writeEntry("StyleID", StatDock::fillBars); + config->sync(); +} + +void StatPopup::setFillShaded() { + fillStyle = StatDock::fillShaded; + + actFillLines->setChecked(false); + actFillBars->setChecked(false); + actFillShaded->setChecked(true); + + for (int i = 0; i < r.size(); i++) { + r[i].dock->setFill(StatDock::fillShaded); + } + + config->setGroup("General Options"); + config->writeEntry("StyleID", StatDock::fillShaded); + config->sync(); +} + +void StatPopup::setSoft(bool set) { + for (int i = 0; i < r.size(); i++) { + r[i].dock->setSoft(set); + } + + config->setGroup("General Options"); + config->writeEntry("Soft", set); + config->sync(); +} + +void StatPopup::setLabelled(bool set) { + for (int i = 0; i < r.size(); i++) { + r[i].dock->setLabelled(set); + } + + config->setGroup("General Options"); + config->writeEntry("Labelled", set); + config->sync(); +} + +void StatPopup::setGrid(bool set) { + for (int i = 0; i < r.size(); i++) { + r[i].dock->setGrid(set); + } + + config->setGroup("General Options"); + config->writeEntry("Grid", set); + config->sync(); +} + +void StatPopup::selectColor() { + // which color? + int whichDock; + if (sscanf(sender()->name(), "Color%d", &whichDock) != 1) + return; + if (whichDock < 0 || whichDock >= r.size()) + return; + + if (r[whichDock].dock) { + QColor ans; + if (KColorDialog::getColor(ans, r[whichDock].color, firstDock()) == + QDialog::Accepted) { + r[whichDock].color = ans; + r[whichDock].dock->setColor(ans); + + config->setGroup("General Options"); + QString n; + n.sprintf("Color%d", whichDock); + config->writeEntry(n, ans); + config->sync(); + } + } +} + +StatDock* StatPopup::firstDock() { + return r.size() > 0 ? r[0].dock : 0; +} + +void StatPopup::startUpdates() { + takeReading(); + timer->start(speed); +} + +void StatPopup::stopUpdates() { + timer->stop(); + fullReading = i18n("Inactive."); +} + +void StatPopup::setupActions() { + config->setGroup("General Options"); + bool bVal; + + bVal = config->readBoolEntry("Active", true); + actActive = new KToggleAction(i18n("&Active"), 0, coll, "active"); + actActive->setChecked(bVal); + connect(actActive, SIGNAL(toggled(bool)), this, SLOT(setActive(bool))); + + actClearHistory = new KAction(i18n("&Clear"), "editdelete", 0, + this, SLOT(clearHistory()), coll, "clear"); + + speed = config->readNumEntry("Speed", DEFAULT_SPEED); + actSpeed = new KAction(i18n("&Speed..."), "speedarrow", 0, + this, SLOT(selectSpeed()), coll, "speed"); + + if (supportSplit) { + bVal = config->readBoolEntry("Split", true); + actSplit = new IconToggleAction(i18n("Sp&lit Graph"), "split", + i18n("Graph Sp&litting Enabled"), "spliton", 0, coll, "split"); + actSplit->setChecked(bVal); + connect(actSplit, SIGNAL(toggled(bool)), this, SLOT(setSplit(bool))); + } + + fillStyle = config->readNumEntry("StyleID", StatDock::fillShaded); + actFillLines = new IconToggleAction(i18n("&Lines"), "lines", "lineson", 0, + this, SLOT(setFillLines()), coll, "filllines"); + actFillLines->setChecked(fillStyle == StatDock::fillLines); + actFillBars = new IconToggleAction(i18n("&Bars"), "bars", "barson", 0, + this, SLOT(setFillBars()), coll, "fillbars"); + actFillBars->setChecked(fillStyle == StatDock::fillBars); + actFillShaded = new IconToggleAction(i18n("&Shaded"), "shaded", "shadedon", + 0, this, SLOT(setFillShaded()), coll, "fillshaded"); + actFillShaded->setChecked(fillStyle == StatDock::fillShaded); + + bVal = config->readBoolEntry("Soft", false); + actSoft = new IconToggleAction(i18n("So&ft Curves"), "soft", + i18n("So&ft Curves Enabled"), "softon", 0, coll, "soft"); + actSoft->setChecked(bVal); + connect(actSoft, SIGNAL(toggled(bool)), this, SLOT(setSoft(bool))); + + bVal = config->readBoolEntry("Labelled", true); + actLabelled= new IconToggleAction(i18n("Show &Labels"), "labels", + i18n("&Labels Enabled"), "labelson", 0, coll, "labelled"); + actLabelled->setChecked(bVal); + connect(actLabelled, SIGNAL(toggled(bool)), this, SLOT(setLabelled(bool))); + + bVal = config->readBoolEntry("Grid", true); + actGrid = new IconToggleAction(i18n("Show &Grid"), "grid", + i18n("&Grid Enabled"), "gridon", 0, coll, "grid"); + actGrid->setChecked(bVal); + connect(actGrid, SIGNAL(toggled(bool)), this, SLOT(setGrid(bool))); + + setupCustomActions(); +} + +void StatPopup::paintEvent(QPaintEvent*) { + QPainter p(this); + + // Draw the border. + p.setPen(colorBorder); + p.drawLine(0, 0, width(), 0); + p.drawLine(0, 1, width(), 1); + p.drawLine(0, 2, 0, height()); + p.drawLine(1, 2, 1, height()); + p.drawLine(width() - 2, 2, width() - 2, height()); + p.drawLine(width() - 1, 2, width() - 1, height()); + p.drawLine(2, height() - 2, width() - 2, height() - 2); + p.drawLine(2, height() - 1, width() - 2, height() - 1); + + // Draw the text. + p.setFont(font()); + p.setPen(colorGroup().foreground()); + p.drawText(rect(), AlignHCenter | AlignVCenter, fullReading); +} + +void StatPopup::mousePressEvent(QMouseEvent* e) { + if(e->button() == RightButton) { + // Hide the pop-up. + hide(); + } else { + // Begin a drag operation. + isDragged = true; + relX = e->x(); + relY = e->y(); + repaint(); + } +} + +void StatPopup::mouseMoveEvent(QMouseEvent* e) { + // In the middle of a drag operation. + move(e->globalX() - relX, e->globalY() - relY); +} + +void StatPopup::mouseReleaseEvent(QMouseEvent* e) { + // The end of a drag operation. + move(e->globalX() - relX, e->globalY() - relY); + isDragged = false; + repaint(); +} + +void StatPopup::closeEvent(QCloseEvent* e) { + // We're about to close. Save the current state for the last time. + savePopupState(); + closing = true; + QWidget::closeEvent(e); +} + +void StatPopup::hideEvent(QHideEvent* e) { + // We're about to hide. Save the current state if we're not + // closing altogether. + if (! closing) + savePopupState(); + QWidget::hideEvent(e); +} + +void StatPopup::showEvent(QShowEvent* e) { + // Make sure we're up-to-date and properly resized. + if (isActive()) + takeReading(); + else + resizeToText(); + + // Window management - fix so a taskbar button doesn't appear + KWin::setState(winId(), NET::SkipTaskbar | NET::SkipPager); + + QWidget::showEvent(e); +} + +void StatPopup::takeReading() { + takeReadingInternal(); + + for (int i = 0; i < r.size(); i++) { + r[i].dock->addPercentReading(r[i].upper, r[i].lower); + } + + if (isVisible()) { + // Only resize if the pop-up is visible; otherwise fullReading + // might be stale anyway so we'll do it when we show the pop-up. + if (resizeRequested) + resizeToText(); + + repaint(); + } +} + +void StatPopup::resizeToText() { + resizeRequested = false; + + QSize size = fontMetrics().size(0, fullReading); + resize(size.width() + 2 * TEXT_EXPANSION_HORIZONTAL, + size.height() + 2 * TEXT_EXPANSION_VERTICAL); + repaint(); +} + +#include "statpopup.moc" diff --git a/kcpuload/kcpuload/statpopup.h b/kcpuload/kcpuload/statpopup.h new file mode 100644 index 0000000..2cd7213 --- /dev/null +++ b/kcpuload/kcpuload/statpopup.h @@ -0,0 +1,319 @@ + +/*************************************************************************** + * * + * KCPULoad and KNetLoad are copyright (c) 1999-2000, Markus Gustavsson * + * (c) 2002, Ben Burton * + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef __STATPOPUP_H +#define __STATPOPUP_H + +#include <qwidget.h> +#include <vector> // sorry, QValueVector::erase() does not call destructors + +class KAction; +class KActionCollection; +class KConfig; +class KPopupMenu; +class KRadioAction; +class KSelectAction; +class KToggleAction; +class QTimer; +class StatDock; + +/** + * A small pop-up window that contains a continually updating display of + * statistics. + * + * This pop-up will be sticky and stay-on-top by default. + * + * Up to two windows docked in the system tray (of class StatDock) can + * be maintained by this pop-up. There should only be one StatPopup + * per application. + * + * Note that initDock() \e must be called when a system tray window is + * created, though it is generally called automatically from the StatDock + * constructor. + * + * Note also that the constructor for this class does \e not call + * setupActions(), readPopupState() or startUpdates(); these must all be + * called by other routines (such as subclass constructors), since they + * require either subclass initialisation or an existing system tray + * window. + */ +class StatPopup : public QWidget { + Q_OBJECT + +public: + /** + * Colour constants. + */ + static const QColor colorBorder; + +public: + /** + * Constructors and destructors. + * + * This constructor will set the config variable but will not read + * any configuration information. See the general class notes also + * for a list of other routines this constructor will not call. + */ + StatPopup(bool useSupportSplit, QWidget *parent = 0, const char *name = 0); + ~StatPopup(); + + /** + * Geometric pop-up state management. + */ + void readPopupState(); + void savePopupState(); + + /** + * Initialises the given system tray window and its context menu. + * + * All global application properties (i.e., properties held by this + * pop-up) will be propagated to the system tray window, and all + * global application actions will be added to the given menu. + * + * Parameter whichDock must be either 0 or 1 to specify whether the + * given system tray window will become window dock[0] or dock[1]. + * + * This routine \e must be called when a system tray window is first + * created, though in general this will be done automatically by the + * StatDock constructor. + */ + virtual void initDock(StatDock* target, KPopupMenu* menu, int whichDock); + + /** + * Is this application currently active (i.e., taking periodic + * readings and displaying them)? + */ + bool isActive() const; + + /** + * Are split diagrams currently enabled? + */ + bool isSplit() const; + + /** + * Returns the frequency of updates in milliseconds. + */ + int getSpeed() const; + +public slots: + /** + * Slots for menu items. + */ + void setActive(bool); + void clearHistory(); + void selectSpeed(); + void setSplit(bool); + void setFillLines(); + void setFillBars(); + void setFillShaded(); + void setSoft(bool); + void setLabelled(bool); + void setGrid(bool); + void selectColor(); + +protected: + /** + * Return a human-readable name and default diagram colour for each + * system tray window. + * The argument given will be either 0 or 1, referring to window + * dock[0] or dock[1] respectively. + */ + virtual QString dockName(int which) const = 0; + virtual QColor defaultDockColor(int which) const = 0; + + /** + * Take a fresh reading. Subclasses must override this routine. + * + * This routine must update the array upper. + * If split readings are enabled, it must also update the array lower. + * If this pop-up is visible, it must also update the string fullReading. + */ + virtual void takeReadingInternal() = 0; + + /** + * Sets up any actions specific to subclasses of StatPopup. + * The global configuration should be read at this point to set the + * initial states of these actions. + * + * This routine will be called during setupActions(). + */ + virtual void setupCustomActions() {} + + /** + * Inserts any menu items specific to subclasses of StatPopup into + * the given menu. If any items are inserted, a separator should + * be inserted after them. + * + * This routine will be called during initDock(). + */ + virtual void insertCustomItems(KPopupMenu*) {} + + /** + * Propagates any properties specific to subclasses of StatPopup to + * the given system tray window during its initialisation. + * + * This routine will be called during initDock(). + */ + virtual void setCustomProperties(StatDock*) {} + + /** + * Returns the first non-null pointer out of dock[0] and dock[1], or + * returns null if both these pointers are null. + */ + StatDock* firstDock(); + + /** + * Start and stop the periodic taking of readings. + */ + void startUpdates(); + void stopUpdates(); + + /** + * Set up the collection of appliation-wide actions. + * The global configuration will be read at this point to set the + * initial states of these actions. + */ + virtual void setupActions(); + + /** + * Request that this pop-up be resized at the next reading according + * to its text contents. The pop-up will be resized \e after the + * reading is taken. + */ + void requestResize(); + + /** + * Custom painting routine. + */ + void paintEvent(QPaintEvent *); + + /** + * Overrides for dragging support. + */ + void mousePressEvent(QMouseEvent *); + void mouseReleaseEvent(QMouseEvent *); + void mouseMoveEvent(QMouseEvent *); + + /** + * Overrides for saving the popup state. + */ + void closeEvent(QCloseEvent *); + void hideEvent(QHideEvent *); + void showEvent(QShowEvent *); + +protected slots: + /** + * Take a fresh reading and update all visual elements accordingly. + */ + void takeReading(); + +protected: + /** + * Configuration and GUI elements. + */ + KConfig* config; + /**< The configuration for the underlying application. */ + + /** + * Contains the readings per CPU. + */ + struct Reading { + StatDock* dock; + /**< The system tray window maintained by this pop-up. + May be null. */ + int upper; + /**< The upper reading taken during the last reading. */ + int lower; + /**< The lower reading taken during the last reading. */ + QColor color; + /**< The colour used in the system tray diagram. */ + KAction* actColor; + /**< The menu item to change the colour of this dock. */ + Reading(); + ~Reading(); + void Init(int which, StatPopup* popup); + }; + std::vector<Reading> r; + /**< The readings maintained by this pop-up. */ + KActionCollection* coll; + /**< The collection of all application-level actions. */ + + QString fullReading; + /**< A full string describing the last reading taken, + to be displayed in this pop-up. */ + +private: + /** + * Resize this pop-up according to its text contents (i.e., the + * variable fullReading). A little extra room will be added to + * accomodate potential minor variations in the text. + */ + void resizeToText(); + +private: + /** + * Update support. + */ + QTimer* timer; + /**< The timer handling periodic updates. */ + int speed; + /**< The frequency of updates in milliseconds. */ + + /* + * Diagram support. + */ + int fillStyle; + /**< The fill style used in the system tray diagrams. */ + bool supportSplit; + /**< Does this application support split diagrams? */ + + /** + * Pop-up support. + */ + int relX; + /**< The X coordinate of this pop-up at the beginning of a drag + operation. */ + int relY; + /**< The Y coordinate of this pop-up at the beginning of a drag + operation. */ + bool isDragged; + /**< Are we in the middle of a drag operation? */ + bool closing; + /**< Have we received a close event? */ + bool resizeRequested; + /**< Has a pop-up resize been requested? */ + + /** + * Actions + */ + KToggleAction* actActive; + KAction* actClearHistory; + KAction* actSpeed; + KToggleAction* actSplit; + KToggleAction* actFillLines; + KToggleAction* actFillBars; + KToggleAction* actFillShaded; + KToggleAction* actSoft; + KToggleAction* actLabelled; + KToggleAction* actGrid; +}; + +inline int StatPopup::getSpeed() const { + return speed; +} + +inline void StatPopup::requestResize() { + resizeRequested = true; +} + +#endif |