|
|
|
/*
|
|
|
|
* memory.cpp
|
|
|
|
*
|
|
|
|
* prints memory-information and shows a graphical display.
|
|
|
|
*
|
|
|
|
* Copyright (c) 1999-2002 Helge Deller <deller@gmx.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.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h> /* for BSD */
|
|
|
|
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqpainter.h>
|
|
|
|
#include <tqdrawutil.h>
|
|
|
|
#include <tqtooltip.h>
|
|
|
|
|
|
|
|
#include <kglobal.h>
|
|
|
|
#include <kdialog.h>
|
|
|
|
#include <kseparator.h>
|
|
|
|
|
|
|
|
#include "memory.h"
|
|
|
|
|
|
|
|
enum { /* entries for Memory_Info[] */
|
|
|
|
TOTAL_MEM = 0, /* total physical memory (without swaps) */
|
|
|
|
FREE_MEM, /* total free physical memory (without swaps) */
|
|
|
|
#if !defined(__svr4__) || !defined(sun)
|
|
|
|
#if !defined(__NetBSD__) && !defined(__OpenBSD__)
|
|
|
|
SHARED_MEM, /* shared memory size */
|
|
|
|
BUFFER_MEM, /* buffered memory size */
|
|
|
|
#else
|
|
|
|
ACTIVE_MEM,
|
|
|
|
INACTIVE_MEM,
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
CACHED_MEM, /* cache memory size (located in ram) */
|
|
|
|
SWAP_MEM, /* total size of all swap-partitions */
|
|
|
|
FREESWAP_MEM, /* free memory in swap-partitions */
|
|
|
|
MEM_LAST_ENTRY
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
all update()-functions should put either
|
|
|
|
their results _OR_ the value NO_MEMORY_INFO into Memory_Info[]
|
|
|
|
*/
|
|
|
|
static t_memsize Memory_Info[MEM_LAST_ENTRY];
|
|
|
|
|
|
|
|
#define MEMORY(x) ((t_memsize) (x)) /* it's easier... */
|
|
|
|
#define NO_MEMORY_INFO MEMORY(-1) /* DO NOT CHANGE */
|
|
|
|
#define ZERO_IF_NO_INFO(value) ((value) != NO_MEMORY_INFO ? (value) : 0)
|
|
|
|
|
|
|
|
|
|
|
|
/******************/
|
|
|
|
/* Implementation */
|
|
|
|
/******************/
|
|
|
|
|
|
|
|
static TQLabel *MemSizeLabel[MEM_LAST_ENTRY][2];
|
|
|
|
|
|
|
|
enum { MEM_RAM_AND_HDD, MEM_RAM, MEM_HDD, MEM_LAST };
|
|
|
|
static TQWidget *Graph[MEM_LAST];
|
|
|
|
static TQLabel *GraphLabel[MEM_LAST];
|
|
|
|
|
|
|
|
#define SPACING 16
|
|
|
|
|
|
|
|
static TQString formatted_unit(t_memsize value)
|
|
|
|
{
|
|
|
|
if (value > (1024 * 1024))
|
|
|
|
if (value > (1024 * 1024 * 1024))
|
|
|
|
return i18n("%1 GB").arg(KGlobal::locale()->formatNumber(value / (1024 * 1024 * 1024.0), 2));
|
|
|
|
else
|
|
|
|
return i18n("%1 MB").arg(KGlobal::locale()->formatNumber(value / (1024 * 1024.0), 2));
|
|
|
|
else
|
|
|
|
return i18n("%1 KB").arg(KGlobal::locale()->formatNumber(value / 1024.0, 2));
|
|
|
|
}
|
|
|
|
|
|
|
|
KMemoryWidget::KMemoryWidget(TQWidget * parent, const char *name)
|
|
|
|
: KCModule(parent, name)
|
|
|
|
{
|
|
|
|
|
|
|
|
KAboutData *about =
|
|
|
|
new KAboutData(I18N_NOOP("kcminfo"),
|
|
|
|
I18N_NOOP("TDE Panel Memory Information Control Module"),
|
|
|
|
0, 0, KAboutData::License_GPL,
|
|
|
|
I18N_NOOP("(c) 1998 - 2002 Helge Deller"));
|
|
|
|
|
|
|
|
about->addAuthor("Helge Deller", 0, "deller@gmx.de");
|
|
|
|
setAboutData( about );
|
|
|
|
|
|
|
|
TQString title, initial_str;
|
|
|
|
TQLabel *Widget = 0;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
ram_colors_initialized =
|
|
|
|
swap_colors_initialized =
|
|
|
|
all_colors_initialized = false;
|
|
|
|
|
|
|
|
setButtons(Help);
|
|
|
|
|
|
|
|
/* default string for no Information... */
|
|
|
|
Not_Available_Text = i18n("Not available.");
|
|
|
|
|
|
|
|
TQVBoxLayout *top = new TQVBoxLayout(this, 0, KDialog::spacingHint());
|
|
|
|
|
|
|
|
TQHBoxLayout *hbox = new TQHBoxLayout();
|
|
|
|
top->addLayout(hbox);
|
|
|
|
|
|
|
|
/* stretch the left side */
|
|
|
|
hbox->addStretch();
|
|
|
|
|
|
|
|
/* first create the Informationtext-Widget */
|
|
|
|
TQVBoxLayout *vbox = new TQVBoxLayout(hbox, 0);
|
|
|
|
for (i = TOTAL_MEM; i < MEM_LAST_ENTRY; ++i) {
|
|
|
|
switch (i) {
|
|
|
|
case TOTAL_MEM:
|
|
|
|
title = i18n("Total physical memory:");
|
|
|
|
break;
|
|
|
|
case FREE_MEM:
|
|
|
|
title = i18n("Free physical memory:");
|
|
|
|
break;
|
|
|
|
#if !defined(__svr4__) || !defined(sun)
|
|
|
|
#if !defined(__NetBSD__) && !defined(__OpenBSD__)
|
|
|
|
case SHARED_MEM:
|
|
|
|
title = i18n("Shared memory:");
|
|
|
|
break;
|
|
|
|
case BUFFER_MEM:
|
|
|
|
title = i18n("Disk buffers:");
|
|
|
|
break;
|
|
|
|
#else
|
|
|
|
case ACTIVE_MEM:
|
|
|
|
title = i18n("Active memory:");
|
|
|
|
break;
|
|
|
|
case INACTIVE_MEM:
|
|
|
|
title = i18n("Inactive memory:");
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
case CACHED_MEM:
|
|
|
|
title = i18n("Disk cache:");
|
|
|
|
break;
|
|
|
|
case SWAP_MEM:
|
|
|
|
vbox->addSpacing(SPACING);
|
|
|
|
title = i18n("Total swap space:");
|
|
|
|
break;
|
|
|
|
case FREESWAP_MEM:
|
|
|
|
title = i18n("Free swap space:");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
title = "";
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
Widget = new TQLabel(title, this);
|
|
|
|
Widget->setAlignment(AlignLeft);
|
|
|
|
vbox->addWidget(Widget, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* then the memory-content-widgets */
|
|
|
|
for (j = 0; j < 2; j++) {
|
|
|
|
vbox = new TQVBoxLayout(hbox, 0);
|
|
|
|
for (i = TOTAL_MEM; i < MEM_LAST_ENTRY; ++i) {
|
|
|
|
if (i == SWAP_MEM)
|
|
|
|
vbox->addSpacing(SPACING);
|
|
|
|
Widget = new TQLabel(this);
|
|
|
|
Widget->setAlignment(AlignRight);
|
|
|
|
MemSizeLabel[i][j] = Widget;
|
|
|
|
vbox->addWidget(Widget, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* stretch the right side */
|
|
|
|
hbox->addStretch();
|
|
|
|
|
|
|
|
KSeparator *line = new KSeparator(KSeparator::HLine, this);
|
|
|
|
top->addWidget(line);
|
|
|
|
|
|
|
|
/* now the Graphics */
|
|
|
|
TQString hint;
|
|
|
|
hbox = new TQHBoxLayout(top, 1);
|
|
|
|
for (i = MEM_RAM_AND_HDD; i < MEM_LAST; i++) {
|
|
|
|
hbox->addSpacing(SPACING);
|
|
|
|
vbox = new TQVBoxLayout(hbox);
|
|
|
|
|
|
|
|
switch (i) {
|
|
|
|
case MEM_RAM_AND_HDD:
|
|
|
|
title = i18n("Total Memory");
|
|
|
|
hint = i18n("This graph gives you an overview of the "
|
|
|
|
"usage of <b>all available memory</b> (the sum of "
|
|
|
|
"physical memory and swap space) in your system.");
|
|
|
|
break;
|
|
|
|
case MEM_RAM:
|
|
|
|
title = i18n("Physical Memory");
|
|
|
|
hint = i18n("This graph gives you an overview of "
|
|
|
|
"the usage of <b>physical memory</b> in your system."
|
|
|
|
"<p>Most operating systems (including Linux) "
|
|
|
|
"will use as much of the available physical "
|
|
|
|
"memory as possible for a disk cache, "
|
|
|
|
"to speed up the reading and writing of files. "
|
|
|
|
"<p>This means that if you are seeing a small amount "
|
|
|
|
"of <b>Free Physical Memory</b> and a large amount of "
|
|
|
|
"<b>Disk Cache</b>, your system is well configured.");
|
|
|
|
break;
|
|
|
|
case MEM_HDD:
|
|
|
|
title = i18n("Swap Space");
|
|
|
|
hint = i18n("Swap space is the <b>virtual memory</b> "
|
|
|
|
"available to the system. "
|
|
|
|
"<p>It will be used when needed, and is provided "
|
|
|
|
"through one or more swap partitions and/or swap files.");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
hint = title = TQString::null;
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (hint.length())
|
|
|
|
hint = "<qt>" + hint + "</qt>";
|
|
|
|
|
|
|
|
Widget = new TQLabel("<b>" + title + "</b>", this);
|
|
|
|
Widget->setAlignment(AlignCenter);
|
|
|
|
TQToolTip::add(Widget, hint);
|
|
|
|
vbox->addWidget(Widget);
|
|
|
|
vbox->addSpacing(SPACING / 2);
|
|
|
|
|
|
|
|
TQWidget *g = new TQWidget(this);
|
|
|
|
g->setMinimumWidth(2 * SPACING);
|
|
|
|
g->setMinimumHeight(3 * SPACING);
|
|
|
|
g->setBackgroundMode(NoBackground);
|
|
|
|
TQToolTip::add(g, hint); // add the tooltip
|
|
|
|
Graph[i] = g;
|
|
|
|
vbox->addWidget(g, 2);
|
|
|
|
vbox->addSpacing(SPACING / 2);
|
|
|
|
|
|
|
|
Widget = new TQLabel(this); /* xx MB used. */
|
|
|
|
Widget->setAlignment(AlignCenter);
|
|
|
|
TQToolTip::add(Widget, hint);
|
|
|
|
GraphLabel[i] = Widget;
|
|
|
|
vbox->addWidget(Widget);
|
|
|
|
}
|
|
|
|
hbox->addSpacing(SPACING);
|
|
|
|
|
|
|
|
timer = new TQTimer(this);
|
|
|
|
timer->start(100);
|
|
|
|
TQObject::connect(timer, TQT_SIGNAL(timeout()), this,
|
|
|
|
TQT_SLOT(update_Values()));
|
|
|
|
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
KMemoryWidget::~KMemoryWidget()
|
|
|
|
{
|
|
|
|
/* stop the timer */
|
|
|
|
timer->stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQString KMemoryWidget::quickHelp() const
|
|
|
|
{
|
|
|
|
return i18n("<h1>Memory Information</h1>"
|
|
|
|
" This display shows you the current memory usage of your system."
|
|
|
|
" The values are updated on a regular basis and give you an"
|
|
|
|
" overview of the physical and virtual used memory." );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Graphical Memory Display */
|
|
|
|
bool KMemoryWidget::Display_Graph(int widgetindex,
|
|
|
|
int count,
|
|
|
|
t_memsize total,
|
|
|
|
t_memsize * used,
|
|
|
|
TQColor * color,
|
|
|
|
TQString *text)
|
|
|
|
{
|
|
|
|
TQWidget *graph = Graph[widgetindex];
|
|
|
|
int width = graph->width();
|
|
|
|
int height = graph->height();
|
|
|
|
TQPixmap pm(width, height);
|
|
|
|
TQPainter paint;
|
|
|
|
|
|
|
|
paint.begin(&pm, this);
|
|
|
|
|
|
|
|
TQPen pen(TQColor(0, 0, 0));
|
|
|
|
|
|
|
|
if (! ZERO_IF_NO_INFO(total)) {
|
|
|
|
paint.fillRect(1, 1, width - 2, height - 2,
|
|
|
|
TQBrush(TQColor(128, 128, 128)));
|
|
|
|
paint.setPen(pen);
|
|
|
|
paint.drawRect(graph->rect());
|
|
|
|
GraphLabel[widgetindex]->setText(Not_Available_Text);
|
|
|
|
paint.end();
|
|
|
|
bitBlt(graph, 0, 0, &pm);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int startline = height-2;
|
|
|
|
int percent, localheight;
|
|
|
|
t_memsize last_used = 0;
|
|
|
|
|
|
|
|
while (count--) {
|
|
|
|
last_used = *used;
|
|
|
|
|
|
|
|
#ifdef HAVE_LONG_LONG
|
|
|
|
percent = (((long long)last_used) * 1000 + 5) / (total * 10);
|
|
|
|
#else
|
|
|
|
/* prevent integer overflow with usage of double type */
|
|
|
|
percent = (int) ((((double)last_used) * 1000 + 5) / (total * 10));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (count)
|
|
|
|
localheight = ((height-2) * percent) / 100;
|
|
|
|
else
|
|
|
|
localheight = startline;
|
|
|
|
|
|
|
|
if (localheight>0) {
|
|
|
|
paint.fillRect(1, startline, width-2, -localheight, *color);
|
|
|
|
|
|
|
|
if (localheight >= SPACING) {
|
|
|
|
paint.drawText(0, startline-localheight, width, localheight,
|
|
|
|
AlignCenter | WordBreak,
|
|
|
|
TQString("%1 %2%").arg(*text).arg(percent));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
startline -= localheight;
|
|
|
|
|
|
|
|
++used;
|
|
|
|
++color;
|
|
|
|
++text;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* draw surrounding box */
|
|
|
|
paint.setPen(pen);
|
|
|
|
TQRect r = graph->rect();
|
|
|
|
qDrawShadePanel(&paint, r.x(), r.y(), r.width(), r.height(), palette().active(), true, 1);
|
|
|
|
paint.end();
|
|
|
|
bitBlt(graph, 0, 0, &pm);
|
|
|
|
|
|
|
|
GraphLabel[widgetindex]->setText(i18n("%1 free").arg(formatted_unit(last_used)));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update_Values() is the main-loop for updating the Memory-Information */
|
|
|
|
void KMemoryWidget::update_Values()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
bool ok1;
|
|
|
|
TQLabel *label;
|
|
|
|
t_memsize used[5];
|
|
|
|
|
|
|
|
update(); /* get the Information from memory_linux, memory_fbsd */
|
|
|
|
|
|
|
|
/* update the byte-strings */
|
|
|
|
for (i = TOTAL_MEM; i < MEM_LAST_ENTRY; i++) {
|
|
|
|
label = MemSizeLabel[i][0];
|
|
|
|
if (Memory_Info[i] == NO_MEMORY_INFO)
|
|
|
|
label->clear();
|
|
|
|
else
|
|
|
|
label->setText(i18n("%1 bytes =").
|
|
|
|
arg(KGlobal::locale()->
|
|
|
|
formatNumber(Memory_Info[i], 0)));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update the MB-strings */
|
|
|
|
for (i = TOTAL_MEM; i < MEM_LAST_ENTRY; i++) {
|
|
|
|
label = MemSizeLabel[i][1];
|
|
|
|
label->setText((Memory_Info[i] != NO_MEMORY_INFO)
|
|
|
|
? formatted_unit(Memory_Info[i])
|
|
|
|
: Not_Available_Text);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* display graphical output (ram, hdd, at last: HDD+RAM) */
|
|
|
|
/* be careful ! Maybe we have not all info available ! */
|
|
|
|
|
|
|
|
/* RAM usage: */
|
|
|
|
/* don't rely on the SHARED_MEM value since it may refer to
|
|
|
|
* the size of the System V sharedmem in 2.4.x. Calculate instead! */
|
|
|
|
|
|
|
|
used[1] = 0;
|
|
|
|
#if !defined(__svr4__) || !defined(sun)
|
|
|
|
#if !defined(__NetBSD__) && !defined(__OpenBSD__)
|
|
|
|
used[1] = ZERO_IF_NO_INFO(Memory_Info[BUFFER_MEM]);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
used[2] = ZERO_IF_NO_INFO(Memory_Info[CACHED_MEM]);
|
|
|
|
used[3] = ZERO_IF_NO_INFO(Memory_Info[FREE_MEM]);
|
|
|
|
used[0] = ZERO_IF_NO_INFO(Memory_Info[TOTAL_MEM]) - used[1] - used[2] - used[3];
|
|
|
|
if (!ram_colors_initialized) {
|
|
|
|
ram_colors_initialized = true;
|
|
|
|
ram_text[0] = i18n("Application Data");
|
|
|
|
ram_colors[0] = COLOR_USED_DATA; /* used+shared */
|
|
|
|
ram_text[1] = i18n("Disk Buffers");
|
|
|
|
ram_colors[1] = COLOR_USED_BUFFER; /* buffers */
|
|
|
|
ram_text[2] = i18n("Disk Cache");
|
|
|
|
ram_colors[2] = COLOR_USED_CACHE; /* cached */
|
|
|
|
ram_text[3] = i18n("Free Physical Memory");
|
|
|
|
ram_colors[3] = COLOR_FREE_MEMORY; /* free */
|
|
|
|
}
|
|
|
|
ok1 = Display_Graph(MEM_RAM, 4, Memory_Info[TOTAL_MEM],
|
|
|
|
used, ram_colors, ram_text);
|
|
|
|
|
|
|
|
/* SWAP usage: */
|
|
|
|
used[1] = ZERO_IF_NO_INFO(Memory_Info[FREESWAP_MEM]);
|
|
|
|
used[0] = ZERO_IF_NO_INFO(Memory_Info[SWAP_MEM]) - used[1];
|
|
|
|
if (!swap_colors_initialized) {
|
|
|
|
swap_colors_initialized = true;
|
|
|
|
swap_text[0] = i18n("Used Swap");
|
|
|
|
swap_colors[0] = COLOR_USED_SWAP; /* used */
|
|
|
|
swap_text[1] = i18n("Free Swap");
|
|
|
|
swap_colors[1] = COLOR_FREE_MEMORY; /* free */
|
|
|
|
}
|
|
|
|
Display_Graph(MEM_HDD, 2, Memory_Info[SWAP_MEM],
|
|
|
|
used, swap_colors, swap_text);
|
|
|
|
|
|
|
|
/* RAM + SWAP usage: */
|
|
|
|
/* used[0] already contains the amount of used swap */
|
|
|
|
used[2] = Memory_Info[FREE_MEM] + ZERO_IF_NO_INFO(Memory_Info[FREESWAP_MEM]);
|
|
|
|
used[1] = Memory_Info[TOTAL_MEM] - Memory_Info[FREE_MEM];
|
|
|
|
if (!all_colors_initialized) {
|
|
|
|
all_colors_initialized = true;
|
|
|
|
all_text[0] = i18n("Used Memory (swap part)");
|
|
|
|
all_colors[0] = COLOR_USED_SWAP; /* used swap */
|
|
|
|
all_text[1] = i18n("Used Memory (physical part)");
|
|
|
|
all_colors[1] = COLOR_USED_RAM; /* used ram */
|
|
|
|
all_text[2] = i18n("Free Memory (total)");
|
|
|
|
all_colors[2] = COLOR_FREE_MEMORY; /* free ram+swap*/
|
|
|
|
}
|
|
|
|
Display_Graph(MEM_RAM_AND_HDD, 3,
|
|
|
|
ok1 ? Memory_Info[TOTAL_MEM] + ZERO_IF_NO_INFO(Memory_Info[SWAP_MEM])
|
|
|
|
: NO_MEMORY_INFO,
|
|
|
|
used, all_colors, all_text);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Include system-specific code */
|
|
|
|
|
|
|
|
#ifdef __linux__
|
|
|
|
#include "memory_linux.cpp"
|
|
|
|
#elif defined(__APPLE__)
|
|
|
|
#include "memory_osx.cpp"
|
|
|
|
#elif defined(sgi) && sgi
|
|
|
|
#include "memory_sgi.cpp"
|
|
|
|
#elif defined(__svr4__) && defined(sun)
|
|
|
|
#include "memory_solaris.cpp"
|
|
|
|
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
|
|
|
#include "memory_fbsd.cpp"
|
|
|
|
#elif defined(__hpux)
|
|
|
|
#include "memory_hpux.cpp"
|
|
|
|
#elif defined(__NetBSD__) || defined(__OpenBSD__)
|
|
|
|
#include "memory_netbsd.cpp"
|
|
|
|
#elif __osf__
|
|
|
|
#include "memory_tru64.cpp"
|
|
|
|
#else
|
|
|
|
|
|
|
|
/* Default for unsupported systems */
|
|
|
|
void KMemoryWidget::update()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = TOTAL_MEM; i < MEM_LAST_ENTRY; ++i)
|
|
|
|
Memory_Info[i] = NO_MEMORY_INFO;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
#include "memory.moc"
|